~stewart/drizzle/embedded-innodb-create-select-transaction-arrgh

« back to all changes in this revision

Viewing changes to plugin/innobase/handler/ha_innodb.cc

Merged embedded-innodb-autoincrement into embedded-innodb-create-select-transaction-arrgh.

Show diffs side-by-side

added added

removed removed

Lines of Context:
179
179
static const long AUTOINC_NO_LOCKING = 2;
180
180
 
181
181
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
182
 
        innobase_log_buffer_size,
183
 
        innobase_additional_mem_pool_size, innobase_file_io_threads,
184
 
        innobase_force_recovery, innobase_open_files,
185
 
        innobase_autoinc_lock_mode;
 
182
  innobase_log_buffer_size,
 
183
  innobase_additional_mem_pool_size, innobase_file_io_threads,
 
184
  innobase_force_recovery, innobase_open_files,
 
185
  innobase_autoinc_lock_mode;
186
186
static ulong innobase_commit_concurrency = 0;
187
187
static ulong innobase_read_io_threads;
188
188
static ulong innobase_write_io_threads;
195
195
/* The default values for the following char* start-up parameters
196
196
are determined in innobase_init below: */
197
197
 
198
 
static char*    innobase_data_home_dir                  = NULL;
199
 
static char*    innobase_data_file_path                 = NULL;
200
 
static char*    innobase_log_group_home_dir             = NULL;
201
 
static char*    innobase_file_format_name               = NULL;
202
 
static char*    innobase_change_buffering               = NULL;
 
198
static char*  innobase_data_home_dir      = NULL;
 
199
static char*  innobase_data_file_path     = NULL;
 
200
static char*  innobase_log_group_home_dir   = NULL;
 
201
static char*  innobase_file_format_name   = NULL;
 
202
static char*  innobase_change_buffering   = NULL;
203
203
 
204
204
/* Note: This variable can be set to on/off and any of the supported
205
205
file formats in the configuration file, but can only be set to any
206
206
of the supported file formats during runtime. */
207
 
static char*    innobase_file_format_check              = NULL;
 
207
static char*  innobase_file_format_check    = NULL;
208
208
 
209
209
/* The following has a misleading name: starting from 4.0.5, this also
210
210
affects Windows: */
211
 
static char*    innobase_unix_file_flush_method         = NULL;
 
211
static char*  innobase_unix_file_flush_method   = NULL;
212
212
 
213
213
/* Below we have boolean-valued start-up parameters, and their default
214
214
values */
215
215
 
216
 
static ulong    innobase_fast_shutdown                  = 1;
 
216
static ulong  innobase_fast_shutdown      = 1;
217
217
#ifdef UNIV_LOG_ARCHIVE
218
 
static my_bool  innobase_log_archive                    = FALSE;
219
 
static char*    innobase_log_arch_dir                   = NULL;
 
218
static my_bool  innobase_log_archive      = FALSE;
 
219
static char*  innobase_log_arch_dir     = NULL;
220
220
#endif /* UNIV_LOG_ARCHIVE */
221
 
static my_bool  innobase_use_doublewrite                = TRUE;
222
 
static my_bool  innobase_use_checksums                  = TRUE;
223
 
static my_bool  innobase_rollback_on_timeout            = FALSE;
224
 
static my_bool  innobase_create_status_file             = FALSE;
225
 
static my_bool  innobase_stats_on_metadata              = TRUE;
226
 
 
227
 
static char*    internal_innobase_data_file_path        = NULL;
228
 
 
229
 
static char*    innodb_version_str = (char*) INNODB_VERSION_STR;
 
221
static my_bool  innobase_use_doublewrite    = TRUE;
 
222
static my_bool  innobase_use_checksums      = TRUE;
 
223
static my_bool  innobase_rollback_on_timeout    = FALSE;
 
224
static my_bool  innobase_create_status_file   = FALSE;
 
225
static my_bool  innobase_stats_on_metadata    = TRUE;
 
226
 
 
227
static char*  internal_innobase_data_file_path  = NULL;
 
228
 
 
229
static char*  innodb_version_str = (char*) INNODB_VERSION_STR;
230
230
 
231
231
/* The following counter is used to convey information to InnoDB
232
232
about server activity: in selects it is not sensible to call
233
233
srv_active_wake_master_thread after each fetch or search, we only do
234
234
it every INNOBASE_WAKE_INTERVAL'th step. */
235
235
 
236
 
#define INNOBASE_WAKE_INTERVAL  32
237
 
static ulong    innobase_active_counter = 0;
238
 
 
239
 
static hash_table_t*    innobase_open_tables;
240
 
 
241
 
#ifdef __NETWARE__      /* some special cleanup for NetWare */
 
236
#define INNOBASE_WAKE_INTERVAL  32
 
237
static ulong  innobase_active_counter = 0;
 
238
 
 
239
static hash_table_t*  innobase_open_tables;
 
240
 
 
241
#ifdef __NETWARE__  /* some special cleanup for NetWare */
242
242
bool nw_panic = FALSE;
243
243
#endif
244
244
 
245
245
/** Allowed values of innodb_change_buffering */
246
246
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
247
 
        "none",         /* IBUF_USE_NONE */
248
 
        "inserts"       /* IBUF_USE_INSERT */
 
247
  "none",   /* IBUF_USE_NONE */
 
248
  "inserts" /* IBUF_USE_INSERT */
249
249
};
250
250
 
251
251
/********************************************************************
279
279
 
280
280
  virtual ~InnobaseEngine()
281
281
  {
282
 
    int err= 0;
 
282
    int err= 0;
283
283
    if (innodb_inited) {
284
284
 
285
285
      srv_fast_shutdown = (ulint) innobase_fast_shutdown;
309
309
  int
310
310
  close_connection(
311
311
/*======================*/
312
 
                        /* out: 0 or error number */
313
 
        Session*        session);       /* in: handle to the MySQL thread of the user
314
 
                        whose resources should be free'd */
 
312
      /* out: 0 or error number */
 
313
  Session*  session); /* in: handle to the MySQL thread of the user
 
314
      whose resources should be free'd */
315
315
 
316
316
  virtual int doSetSavepoint(Session* session,
317
317
                                 drizzled::NamedSavepoint &savepoint);
336
336
  int
337
337
  doXaPrepare(
338
338
  /*================*/
339
 
                        /* out: 0 or error number */
340
 
        Session*        session,        /* in: handle to the MySQL thread of the user
341
 
                        whose XA transaction should be prepared */
342
 
        bool    all);   /* in: TRUE - commit transaction
343
 
                        FALSE - the current SQL statement ended */
 
339
        /* out: 0 or error number */
 
340
    Session*  session,  /* in: handle to the MySQL thread of the user
 
341
        whose XA transaction should be prepared */
 
342
    bool  all); /* in: TRUE - commit transaction
 
343
        FALSE - the current SQL statement ended */
344
344
  /***********************************************************************
345
345
  This function is used to recover X/Open XA distributed transactions   */
346
346
  virtual
347
347
  int
348
348
  doXaRecover(
349
349
  /*================*/
350
 
                                /* out: number of prepared transactions
351
 
                                stored in xid_list */
352
 
        ::drizzled::XID*        xid_list,       /* in/out: prepared transactions */
353
 
        size_t len);            /* in: number of slots in xid_list */
 
350
          /* out: number of prepared transactions
 
351
          stored in xid_list */
 
352
    ::drizzled::XID*  xid_list, /* in/out: prepared transactions */
 
353
    size_t len);    /* in: number of slots in xid_list */
354
354
  /***********************************************************************
355
355
  This function is used to commit one X/Open XA distributed transaction
356
356
  which is in the prepared state */
358
358
  int
359
359
  doXaCommitXid(
360
360
  /*===================*/
361
 
                        /* out: 0 or error number */
362
 
        ::drizzled::XID*        xid);   /* in: X/Open XA transaction identification */
 
361
        /* out: 0 or error number */
 
362
    ::drizzled::XID*  xid); /* in: X/Open XA transaction identification */
363
363
  /***********************************************************************
364
364
  This function is used to rollback one X/Open XA distributed transaction
365
365
  which is in the prepared state */
367
367
  int
368
368
  doXaRollbackXid(
369
369
  /*=====================*/
370
 
                        /* out: 0 or error number */
371
 
        ::drizzled::XID *xid);  /* in: X/Open XA transaction identification */
 
370
        /* out: 0 or error number */
 
371
    ::drizzled::XID *xid);  /* in: X/Open XA transaction identification */
372
372
 
373
373
  virtual Cursor *create(TableShare &table,
374
374
                         memory::Root *mem_root)
381
381
  bool
382
382
  doDropSchema(
383
383
  /*===================*/
384
 
                        /* out: error number */
385
 
        SchemaIdentifier        &identifier);   /* in: database path; inside InnoDB the name
386
 
                        of the last directory in the path is used as
387
 
                        the database name: for example, in 'mysql/data/test'
388
 
                        the database name is 'test' */
 
384
        /* out: error number */
 
385
    SchemaIdentifier  &identifier); /* in: database path; inside InnoDB the name
 
386
        of the last directory in the path is used as
 
387
        the database name: for example, in 'mysql/data/test'
 
388
        the database name is 'test' */
389
389
 
390
390
  /********************************************************************
391
391
  Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
394
394
  bool
395
395
  flush_logs();
396
396
  /*================*/
397
 
                                /* out: TRUE if error */
 
397
          /* out: TRUE if error */
398
398
  
399
399
  /****************************************************************************
400
400
  Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
403
403
  bool
404
404
  show_status(
405
405
  /*===============*/
406
 
        Session*        session,        /* in: the MySQL query thread of the caller */
407
 
        stat_print_fn *stat_print,
408
 
        enum ha_stat_type stat_type);
 
406
    Session*  session,  /* in: the MySQL query thread of the caller */
 
407
    stat_print_fn *stat_print,
 
408
  enum ha_stat_type stat_type);
409
409
 
410
410
  virtual
411
411
  int
412
412
  doReleaseTemporaryLatches(
413
413
  /*===============================*/
414
 
                                /* out: 0 */
415
 
        Session*                session);       /* in: MySQL thread */
 
414
        /* out: 0 */
 
415
  Session*    session); /* in: MySQL thread */
416
416
 
417
417
 
418
418
  const char** bas_ext() const {
419
 
        return(ha_innobase_exts);
 
419
  return(ha_innobase_exts);
420
420
  }
421
421
 
422
422
  UNIV_INTERN int doCreateTable(Session &session,
447
447
                           drizzled::message::Table &table_proto);
448
448
 
449
449
  void doGetTableNames(drizzled::CachedDirectory &directory,
450
 
                       drizzled::SchemaIdentifier &schema_identifier,
 
450
           drizzled::SchemaIdentifier &schema_identifier,
451
451
                       std::set<std::string> &set_of_names);
452
452
 
453
453
  bool doDoesTableExist(drizzled::Session& session, drizzled::TableIdentifier &identifier);
567
567
 
568
568
/************************************************************//**
569
569
Validate the file format name and return its corresponding id.
570
 
@return valid file format id */
 
570
@return valid file format id */
571
571
static
572
572
uint
573
573
innobase_file_format_name_lookup(
574
574
/*=============================*/
575
 
        const char*     format_name);           /*!< in: pointer to file format
576
 
                                                name */
 
575
  const char* format_name);   /*!< in: pointer to file format
 
576
            name */
577
577
/************************************************************//**
578
578
Validate the file format check config parameters, as a side effect it
579
579
sets the srv_check_file_format_at_startup variable.
580
 
@return true if one of  "on" or "off" */
 
580
@return true if one of  "on" or "off" */
581
581
static
582
582
bool
583
583
innobase_file_format_check_on_off(
584
584
/*==============================*/
585
 
        const char*     format_check);          /*!< in: parameter value */
 
585
  const char* format_check);    /*!< in: parameter value */
586
586
/************************************************************//**
587
587
Validate the file format check config parameters, as a side effect it
588
588
sets the srv_check_file_format_at_startup variable.
589
 
@return true if valid config value */
 
589
@return true if valid config value */
590
590
static
591
591
bool
592
592
innobase_file_format_check_validate(
593
593
/*================================*/
594
 
        const char*     format_check);          /*!< in: parameter value */
 
594
  const char* format_check);    /*!< in: parameter value */
595
595
 
596
596
static const char innobase_engine_name[]= "InnoDB";
597
597
 
598
598
/*************************************************************//**
599
599
Check for a valid value of innobase_commit_concurrency.
600
 
@return 0 for valid innodb_commit_concurrency */
 
600
@return 0 for valid innodb_commit_concurrency */
601
601
static
602
602
int
603
603
innobase_commit_concurrency_validate(
604
604
/*=================================*/
605
 
        Session*                        ,       /*!< in: thread handle */
606
 
        drizzle_sys_var*        ,       /*!< in: pointer to system
607
 
                                                variable */
608
 
        void*                           save,   /*!< out: immediate result
609
 
                                                for update function */
610
 
        drizzle_value*          value)  /*!< in: incoming string */
 
605
  Session*      , /*!< in: thread handle */
 
606
  drizzle_sys_var*  , /*!< in: pointer to system
 
607
            variable */
 
608
  void*       save, /*!< out: immediate result
 
609
            for update function */
 
610
  drizzle_value*    value)  /*!< in: incoming string */
611
611
{
612
 
        int64_t         intbuf;
613
 
        ulong           commit_concurrency;
614
 
 
615
 
        if (value->val_int(value, &intbuf)) {
616
 
                /* The value is NULL. That is invalid. */
617
 
                return(1);
618
 
        }
619
 
 
620
 
        *reinterpret_cast<ulong*>(save) = commit_concurrency
621
 
                = static_cast<ulong>(intbuf);
622
 
 
623
 
        /* Allow the value to be updated, as long as it remains zero
624
 
        or nonzero. */
625
 
        return(!(!commit_concurrency == !innobase_commit_concurrency));
 
612
  int64_t   intbuf;
 
613
  ulong   commit_concurrency;
 
614
 
 
615
  if (value->val_int(value, &intbuf)) {
 
616
    /* The value is NULL. That is invalid. */
 
617
    return(1);
 
618
  }
 
619
 
 
620
  *reinterpret_cast<ulong*>(save) = commit_concurrency
 
621
    = static_cast<ulong>(intbuf);
 
622
 
 
623
  /* Allow the value to be updated, as long as it remains zero
 
624
  or nonzero. */
 
625
  return(!(!commit_concurrency == !innobase_commit_concurrency));
626
626
}
627
627
 
628
628
static DRIZZLE_SessionVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
650
650
void
651
651
innobase_commit_low(
652
652
/*================*/
653
 
        trx_t*  trx);   /*!< in: transaction handle */
 
653
  trx_t*  trx); /*!< in: transaction handle */
654
654
 
655
655
static drizzle_show_var innodb_status_variables[]= {
656
656
  {"buffer_pool_pages_data",
657
 
  (char*) &export_vars.innodb_buffer_pool_pages_data,     SHOW_LONG},
 
657
  (char*) &export_vars.innodb_buffer_pool_pages_data,   SHOW_LONG},
658
658
  {"buffer_pool_pages_dirty",
659
 
  (char*) &export_vars.innodb_buffer_pool_pages_dirty,    SHOW_LONG},
 
659
  (char*) &export_vars.innodb_buffer_pool_pages_dirty,    SHOW_LONG},
660
660
  {"buffer_pool_pages_flushed",
661
661
  (char*) &export_vars.innodb_buffer_pool_pages_flushed,  SHOW_LONG},
662
662
  {"buffer_pool_pages_free",
663
 
  (char*) &export_vars.innodb_buffer_pool_pages_free,     SHOW_LONG},
 
663
  (char*) &export_vars.innodb_buffer_pool_pages_free,   SHOW_LONG},
664
664
#ifdef UNIV_DEBUG
665
665
  {"buffer_pool_pages_latched",
666
666
  (char*) &export_vars.innodb_buffer_pool_pages_latched,  SHOW_LONG},
667
667
#endif /* UNIV_DEBUG */
668
668
  {"buffer_pool_pages_misc",
669
 
  (char*) &export_vars.innodb_buffer_pool_pages_misc,     SHOW_LONG},
 
669
  (char*) &export_vars.innodb_buffer_pool_pages_misc,   SHOW_LONG},
670
670
  {"buffer_pool_pages_total",
671
 
  (char*) &export_vars.innodb_buffer_pool_pages_total,    SHOW_LONG},
 
671
  (char*) &export_vars.innodb_buffer_pool_pages_total,    SHOW_LONG},
672
672
  {"buffer_pool_read_ahead_rnd",
673
673
  (char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG},
674
674
  {"buffer_pool_read_ahead_seq",
676
676
  {"buffer_pool_read_requests",
677
677
  (char*) &export_vars.innodb_buffer_pool_read_requests,  SHOW_LONG},
678
678
  {"buffer_pool_reads",
679
 
  (char*) &export_vars.innodb_buffer_pool_reads,          SHOW_LONG},
 
679
  (char*) &export_vars.innodb_buffer_pool_reads,    SHOW_LONG},
680
680
  {"buffer_pool_wait_free",
681
 
  (char*) &export_vars.innodb_buffer_pool_wait_free,      SHOW_LONG},
 
681
  (char*) &export_vars.innodb_buffer_pool_wait_free,    SHOW_LONG},
682
682
  {"buffer_pool_write_requests",
683
683
  (char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
684
684
  {"data_fsyncs",
685
 
  (char*) &export_vars.innodb_data_fsyncs,                SHOW_LONG},
 
685
  (char*) &export_vars.innodb_data_fsyncs,      SHOW_LONG},
686
686
  {"data_pending_fsyncs",
687
 
  (char*) &export_vars.innodb_data_pending_fsyncs,        SHOW_LONG},
 
687
  (char*) &export_vars.innodb_data_pending_fsyncs,    SHOW_LONG},
688
688
  {"data_pending_reads",
689
 
  (char*) &export_vars.innodb_data_pending_reads,         SHOW_LONG},
 
689
  (char*) &export_vars.innodb_data_pending_reads,   SHOW_LONG},
690
690
  {"data_pending_writes",
691
 
  (char*) &export_vars.innodb_data_pending_writes,        SHOW_LONG},
 
691
  (char*) &export_vars.innodb_data_pending_writes,    SHOW_LONG},
692
692
  {"data_read",
693
 
  (char*) &export_vars.innodb_data_read,                  SHOW_LONG},
 
693
  (char*) &export_vars.innodb_data_read,      SHOW_LONG},
694
694
  {"data_reads",
695
 
  (char*) &export_vars.innodb_data_reads,                 SHOW_LONG},
 
695
  (char*) &export_vars.innodb_data_reads,     SHOW_LONG},
696
696
  {"data_writes",
697
 
  (char*) &export_vars.innodb_data_writes,                SHOW_LONG},
 
697
  (char*) &export_vars.innodb_data_writes,      SHOW_LONG},
698
698
  {"data_written",
699
 
  (char*) &export_vars.innodb_data_written,               SHOW_LONG},
 
699
  (char*) &export_vars.innodb_data_written,     SHOW_LONG},
700
700
  {"dblwr_pages_written",
701
 
  (char*) &export_vars.innodb_dblwr_pages_written,        SHOW_LONG},
 
701
  (char*) &export_vars.innodb_dblwr_pages_written,    SHOW_LONG},
702
702
  {"dblwr_writes",
703
 
  (char*) &export_vars.innodb_dblwr_writes,               SHOW_LONG},
 
703
  (char*) &export_vars.innodb_dblwr_writes,     SHOW_LONG},
704
704
  {"have_atomic_builtins",
705
 
  (char*) &export_vars.innodb_have_atomic_builtins,       SHOW_BOOL},
 
705
  (char*) &export_vars.innodb_have_atomic_builtins,   SHOW_BOOL},
706
706
  {"log_waits",
707
 
  (char*) &export_vars.innodb_log_waits,                  SHOW_LONG},
 
707
  (char*) &export_vars.innodb_log_waits,      SHOW_LONG},
708
708
  {"log_write_requests",
709
 
  (char*) &export_vars.innodb_log_write_requests,         SHOW_LONG},
 
709
  (char*) &export_vars.innodb_log_write_requests,   SHOW_LONG},
710
710
  {"log_writes",
711
 
  (char*) &export_vars.innodb_log_writes,                 SHOW_LONG},
 
711
  (char*) &export_vars.innodb_log_writes,     SHOW_LONG},
712
712
  {"os_log_fsyncs",
713
 
  (char*) &export_vars.innodb_os_log_fsyncs,              SHOW_LONG},
 
713
  (char*) &export_vars.innodb_os_log_fsyncs,      SHOW_LONG},
714
714
  {"os_log_pending_fsyncs",
715
 
  (char*) &export_vars.innodb_os_log_pending_fsyncs,      SHOW_LONG},
 
715
  (char*) &export_vars.innodb_os_log_pending_fsyncs,    SHOW_LONG},
716
716
  {"os_log_pending_writes",
717
 
  (char*) &export_vars.innodb_os_log_pending_writes,      SHOW_LONG},
 
717
  (char*) &export_vars.innodb_os_log_pending_writes,    SHOW_LONG},
718
718
  {"os_log_written",
719
 
  (char*) &export_vars.innodb_os_log_written,             SHOW_LONG},
 
719
  (char*) &export_vars.innodb_os_log_written,     SHOW_LONG},
720
720
  {"page_size",
721
 
  (char*) &export_vars.innodb_page_size,                  SHOW_LONG},
 
721
  (char*) &export_vars.innodb_page_size,      SHOW_LONG},
722
722
  {"pages_created",
723
 
  (char*) &export_vars.innodb_pages_created,              SHOW_LONG},
 
723
  (char*) &export_vars.innodb_pages_created,      SHOW_LONG},
724
724
  {"pages_read",
725
 
  (char*) &export_vars.innodb_pages_read,                 SHOW_LONG},
 
725
  (char*) &export_vars.innodb_pages_read,     SHOW_LONG},
726
726
  {"pages_written",
727
 
  (char*) &export_vars.innodb_pages_written,              SHOW_LONG},
 
727
  (char*) &export_vars.innodb_pages_written,      SHOW_LONG},
728
728
  {"row_lock_current_waits",
729
 
  (char*) &export_vars.innodb_row_lock_current_waits,     SHOW_LONG},
 
729
  (char*) &export_vars.innodb_row_lock_current_waits,   SHOW_LONG},
730
730
  {"row_lock_time",
731
 
  (char*) &export_vars.innodb_row_lock_time,              SHOW_LONGLONG},
 
731
  (char*) &export_vars.innodb_row_lock_time,      SHOW_LONGLONG},
732
732
  {"row_lock_time_avg",
733
 
  (char*) &export_vars.innodb_row_lock_time_avg,          SHOW_LONG},
 
733
  (char*) &export_vars.innodb_row_lock_time_avg,    SHOW_LONG},
734
734
  {"row_lock_time_max",
735
 
  (char*) &export_vars.innodb_row_lock_time_max,          SHOW_LONG},
 
735
  (char*) &export_vars.innodb_row_lock_time_max,    SHOW_LONG},
736
736
  {"row_lock_waits",
737
 
  (char*) &export_vars.innodb_row_lock_waits,             SHOW_LONG},
 
737
  (char*) &export_vars.innodb_row_lock_waits,     SHOW_LONG},
738
738
  {"rows_deleted",
739
 
  (char*) &export_vars.innodb_rows_deleted,               SHOW_LONG},
 
739
  (char*) &export_vars.innodb_rows_deleted,     SHOW_LONG},
740
740
  {"rows_inserted",
741
 
  (char*) &export_vars.innodb_rows_inserted,              SHOW_LONG},
 
741
  (char*) &export_vars.innodb_rows_inserted,      SHOW_LONG},
742
742
  {"rows_read",
743
 
  (char*) &export_vars.innodb_rows_read,                  SHOW_LONG},
 
743
  (char*) &export_vars.innodb_rows_read,      SHOW_LONG},
744
744
  {"rows_updated",
745
 
  (char*) &export_vars.innodb_rows_updated,               SHOW_LONG},
 
745
  (char*) &export_vars.innodb_rows_updated,     SHOW_LONG},
746
746
  {NULL, NULL, SHOW_LONG}
747
747
};
748
748
 
805
805
 
806
806
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
807
807
         in non-Cursor code.
808
 
@return true if session is the replication thread */
 
808
@return true if session is the replication thread */
809
809
extern "C" UNIV_INTERN
810
810
ibool
811
811
thd_is_replication_slave_thread(
812
812
/*============================*/
813
 
        void*   )       /*!< in: thread handle (Session*) */
 
813
  void* ) /*!< in: thread handle (Session*) */
814
814
{
815
 
        return false;
 
815
  return false;
816
816
}
817
817
 
818
818
/******************************************************************//**
822
822
void
823
823
innodb_srv_conc_enter_innodb(
824
824
/*=========================*/
825
 
        trx_t*  trx)    /*!< in: transaction handle */
 
825
  trx_t*  trx)  /*!< in: transaction handle */
826
826
{
827
 
        if (UNIV_LIKELY(!srv_thread_concurrency)) {
828
 
 
829
 
                return;
830
 
        }
831
 
 
832
 
        srv_conc_enter_innodb(trx);
 
827
  if (UNIV_LIKELY(!srv_thread_concurrency)) {
 
828
 
 
829
    return;
 
830
  }
 
831
 
 
832
  srv_conc_enter_innodb(trx);
833
833
}
834
834
 
835
835
/******************************************************************//**
839
839
void
840
840
innodb_srv_conc_exit_innodb(
841
841
/*========================*/
842
 
        trx_t*  trx)    /*!< in: transaction handle */
 
842
  trx_t*  trx)  /*!< in: transaction handle */
843
843
{
844
 
        if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
845
 
 
846
 
                return;
847
 
        }
848
 
 
849
 
        srv_conc_exit_innodb(trx);
 
844
  if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
 
845
 
 
846
    return;
 
847
  }
 
848
 
 
849
  srv_conc_exit_innodb(trx);
850
850
}
851
851
 
852
852
/******************************************************************//**
858
858
void
859
859
innobase_release_stat_resources(
860
860
/*============================*/
861
 
        trx_t*  trx)    /*!< in: transaction object */
 
861
  trx_t*  trx)  /*!< in: transaction object */
862
862
{
863
 
        if (trx->has_search_latch) {
864
 
                trx_search_latch_release_if_reserved(trx);
865
 
        }
866
 
 
867
 
        if (trx->declared_to_be_inside_innodb) {
868
 
                /* Release our possible ticket in the FIFO */
869
 
 
870
 
                srv_conc_force_exit_innodb(trx);
871
 
        }
 
863
  if (trx->has_search_latch) {
 
864
    trx_search_latch_release_if_reserved(trx);
 
865
  }
 
866
 
 
867
  if (trx->declared_to_be_inside_innodb) {
 
868
    /* Release our possible ticket in the FIFO */
 
869
 
 
870
    srv_conc_force_exit_innodb(trx);
 
871
  }
872
872
}
873
873
 
874
874
/******************************************************************//**
879
879
 
880
880
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
881
881
         in non-Cursor code.
882
 
@return true if non-transactional tables have been edited */
 
882
@return true if non-transactional tables have been edited */
883
883
extern "C" UNIV_INTERN
884
884
ibool
885
885
thd_has_edited_nontrans_tables(
886
886
/*===========================*/
887
 
        void*           session)        /*!< in: thread handle (Session*) */
 
887
  void*   session)  /*!< in: thread handle (Session*) */
888
888
{
889
 
        return((ibool) session_non_transactional_update((Session*) session));
 
889
  return((ibool) session_non_transactional_update((Session*) session));
890
890
}
891
891
 
892
892
/******************************************************************//**
893
893
Returns true if the thread is executing a SELECT statement.
894
 
@return true if session is executing SELECT */
 
894
@return true if session is executing SELECT */
895
895
extern "C" UNIV_INTERN
896
896
ibool
897
897
thd_is_select(
898
898
/*==========*/
899
 
        const void*     session)        /*!< in: thread handle (Session*) */
 
899
  const void* session)  /*!< in: thread handle (Session*) */
900
900
{
901
 
        return(session_sql_command((const Session*) session) == SQLCOM_SELECT);
 
901
  return(session_sql_command((const Session*) session) == SQLCOM_SELECT);
902
902
}
903
903
 
904
904
/******************************************************************//**
905
905
Returns true if the thread supports XA,
906
906
global value of innodb_supports_xa if session is NULL.
907
 
@return true if session has XA support */
 
907
@return true if session has XA support */
908
908
extern "C" UNIV_INTERN
909
909
ibool
910
910
thd_supports_xa(
911
911
/*============*/
912
 
        void*   session)        /*!< in: thread handle (Session*), or NULL to query
913
 
                                the global innodb_supports_xa */
 
912
  void* session)  /*!< in: thread handle (Session*), or NULL to query
 
913
        the global innodb_supports_xa */
914
914
{
915
 
        return(SessionVAR((Session*) session, support_xa));
 
915
  return(SessionVAR((Session*) session, support_xa));
916
916
}
917
917
 
918
918
/******************************************************************//**
919
919
Returns the lock wait timeout for the current connection.
920
 
@return the lock wait timeout, in seconds */
 
920
@return the lock wait timeout, in seconds */
921
921
extern "C" UNIV_INTERN
922
922
ulong
923
923
thd_lock_wait_timeout(
924
924
/*==================*/
925
 
        void*   session)        /*!< in: thread handle (Session*), or NULL to query
926
 
                        the global innodb_lock_wait_timeout */
 
925
  void* session)  /*!< in: thread handle (Session*), or NULL to query
 
926
      the global innodb_lock_wait_timeout */
927
927
{
928
 
        /* According to <drizzle/plugin.h>, passing session == NULL
929
 
        returns the global value of the session variable. */
930
 
        return(SessionVAR((Session*) session, lock_wait_timeout));
 
928
  /* According to <drizzle/plugin.h>, passing session == NULL
 
929
  returns the global value of the session variable. */
 
930
  return(SessionVAR((Session*) session, lock_wait_timeout));
931
931
}
932
932
 
933
933
/********************************************************************//**
934
934
Obtain the InnoDB transaction of a MySQL thread.
935
 
@return reference to transaction pointer */
 
935
@return reference to transaction pointer */
936
936
static inline
937
937
trx_t*&
938
938
session_to_trx(
939
939
/*=======*/
940
 
        Session*        session)        /*!< in: Drizzle Session */
 
940
  Session*  session)  /*!< in: Drizzle Session */
941
941
{
942
 
        return *(trx_t**) session->getEngineData(innodb_engine_ptr);
 
942
  return *(trx_t**) session->getEngineData(innodb_engine_ptr);
943
943
}
944
944
 
945
945
/********************************************************************//**
946
946
Call this function when mysqld passes control to the client. That is to
947
947
avoid deadlocks on the adaptive hash S-latch possibly held by session. For more
948
948
documentation, see Cursor.cc.
949
 
@return 0 */
 
949
@return 0 */
950
950
int
951
951
InnobaseEngine::doReleaseTemporaryLatches(
952
952
/*===============================*/
953
 
        Session*                session)        /*!< in: MySQL thread */
 
953
  Session*    session)  /*!< in: MySQL thread */
954
954
{
955
 
        trx_t*  trx;
956
 
 
957
 
        assert(this == innodb_engine_ptr);
958
 
 
959
 
        if (!innodb_inited) {
960
 
 
961
 
                return(0);
962
 
        }
963
 
 
964
 
        trx = session_to_trx(session);
965
 
 
966
 
        if (trx) {
967
 
                innobase_release_stat_resources(trx);
968
 
        }
969
 
        return(0);
 
955
  trx_t*  trx;
 
956
 
 
957
  assert(this == innodb_engine_ptr);
 
958
 
 
959
  if (!innodb_inited) {
 
960
 
 
961
    return(0);
 
962
  }
 
963
 
 
964
  trx = session_to_trx(session);
 
965
 
 
966
  if (trx) {
 
967
    innobase_release_stat_resources(trx);
 
968
  }
 
969
  return(0);
970
970
}
971
971
 
972
972
/********************************************************************//**
979
979
innobase_active_small(void)
980
980
/*=======================*/
981
981
{
982
 
        innobase_active_counter++;
 
982
  innobase_active_counter++;
983
983
 
984
 
        if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
985
 
                srv_active_wake_master_thread();
986
 
        }
 
984
  if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
 
985
    srv_active_wake_master_thread();
 
986
  }
987
987
}
988
988
 
989
989
/********************************************************************//**
990
990
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
991
991
about a possible transaction rollback inside InnoDB caused by a lock wait
992
992
timeout or a deadlock.
993
 
@return MySQL error code */
 
993
@return MySQL error code */
994
994
extern "C" UNIV_INTERN
995
995
int
996
996
convert_error_code_to_mysql(
997
997
/*========================*/
998
 
        int             error,  /*!< in: InnoDB error code */
999
 
        ulint           flags,  /*!< in: InnoDB table flags, or 0 */
1000
 
        Session*        session)/*!< in: user thread handle or NULL */
 
998
  int   error,  /*!< in: InnoDB error code */
 
999
  ulint   flags,  /*!< in: InnoDB table flags, or 0 */
 
1000
  Session*  session)/*!< in: user thread handle or NULL */
1001
1001
{
1002
 
        switch (error) {
1003
 
        case DB_SUCCESS:
1004
 
                return(0);
1005
 
 
1006
 
        case DB_ERROR:
1007
 
        default:
1008
 
                return(-1); /* unspecified error */
1009
 
 
1010
 
        case DB_DUPLICATE_KEY:
1011
 
                return(HA_ERR_FOUND_DUPP_KEY);
1012
 
 
1013
 
        case DB_FOREIGN_DUPLICATE_KEY:
1014
 
                return(HA_ERR_FOREIGN_DUPLICATE_KEY);
1015
 
 
1016
 
        case DB_MISSING_HISTORY:
1017
 
                return(HA_ERR_TABLE_DEF_CHANGED);
1018
 
 
1019
 
        case DB_RECORD_NOT_FOUND:
1020
 
                return(HA_ERR_NO_ACTIVE_RECORD);
1021
 
 
1022
 
        case DB_DEADLOCK:
1023
 
                /* Since we rolled back the whole transaction, we must
1024
 
                tell it also to MySQL so that MySQL knows to empty the
1025
 
                cached binlog for this transaction */
 
1002
  switch (error) {
 
1003
  case DB_SUCCESS:
 
1004
    return(0);
 
1005
 
 
1006
  case DB_ERROR:
 
1007
  default:
 
1008
    return(-1); /* unspecified error */
 
1009
 
 
1010
  case DB_DUPLICATE_KEY:
 
1011
    return(HA_ERR_FOUND_DUPP_KEY);
 
1012
 
 
1013
  case DB_FOREIGN_DUPLICATE_KEY:
 
1014
    return(HA_ERR_FOREIGN_DUPLICATE_KEY);
 
1015
 
 
1016
  case DB_MISSING_HISTORY:
 
1017
    return(HA_ERR_TABLE_DEF_CHANGED);
 
1018
 
 
1019
  case DB_RECORD_NOT_FOUND:
 
1020
    return(HA_ERR_NO_ACTIVE_RECORD);
 
1021
 
 
1022
  case DB_DEADLOCK:
 
1023
    /* Since we rolled back the whole transaction, we must
 
1024
    tell it also to MySQL so that MySQL knows to empty the
 
1025
    cached binlog for this transaction */
1026
1026
 
1027
1027
                session_mark_transaction_to_rollback(session, TRUE);
1028
1028
 
1029
 
                return(HA_ERR_LOCK_DEADLOCK);
 
1029
    return(HA_ERR_LOCK_DEADLOCK);
1030
1030
 
1031
 
        case DB_LOCK_WAIT_TIMEOUT:
1032
 
                /* Starting from 5.0.13, we let MySQL just roll back the
1033
 
                latest SQL statement in a lock wait timeout. Previously, we
1034
 
                rolled back the whole transaction. */
 
1031
  case DB_LOCK_WAIT_TIMEOUT:
 
1032
    /* Starting from 5.0.13, we let MySQL just roll back the
 
1033
    latest SQL statement in a lock wait timeout. Previously, we
 
1034
    rolled back the whole transaction. */
1035
1035
 
1036
1036
                session_mark_transaction_to_rollback(session,
1037
1037
                                             (bool)row_rollback_on_timeout);
1038
1038
 
1039
 
                return(HA_ERR_LOCK_WAIT_TIMEOUT);
1040
 
 
1041
 
        case DB_NO_REFERENCED_ROW:
1042
 
                return(HA_ERR_NO_REFERENCED_ROW);
1043
 
 
1044
 
        case DB_ROW_IS_REFERENCED:
1045
 
                return(HA_ERR_ROW_IS_REFERENCED);
1046
 
 
1047
 
        case DB_CANNOT_ADD_CONSTRAINT:
1048
 
                return(HA_ERR_CANNOT_ADD_FOREIGN);
1049
 
 
1050
 
        case DB_CANNOT_DROP_CONSTRAINT:
1051
 
 
1052
 
                return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
1053
 
                                                misleading, a new MySQL error
1054
 
                                                code should be introduced */
1055
 
 
1056
 
        case DB_COL_APPEARS_TWICE_IN_INDEX:
1057
 
        case DB_CORRUPTION:
1058
 
                return(HA_ERR_CRASHED);
1059
 
 
1060
 
        case DB_OUT_OF_FILE_SPACE:
1061
 
                return(HA_ERR_RECORD_FILE_FULL);
1062
 
 
1063
 
        case DB_TABLE_IS_BEING_USED:
1064
 
                return(HA_ERR_WRONG_COMMAND);
1065
 
 
1066
 
        case DB_TABLE_NOT_FOUND:
1067
 
                return(HA_ERR_NO_SUCH_TABLE);
1068
 
 
1069
 
        case DB_TOO_BIG_RECORD:
1070
 
                my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
1071
 
                         page_get_free_space_of_empty(flags
1072
 
                                                      & DICT_TF_COMPACT) / 2);
1073
 
                return(HA_ERR_TO_BIG_ROW);
1074
 
 
1075
 
        case DB_NO_SAVEPOINT:
1076
 
                return(HA_ERR_NO_SAVEPOINT);
1077
 
 
1078
 
        case DB_LOCK_TABLE_FULL:
1079
 
                /* Since we rolled back the whole transaction, we must
1080
 
                tell it also to MySQL so that MySQL knows to empty the
1081
 
                cached binlog for this transaction */
1082
 
 
1083
 
                session_mark_transaction_to_rollback(session, TRUE);
1084
 
 
1085
 
                return(HA_ERR_LOCK_TABLE_FULL);
1086
 
 
1087
 
        case DB_PRIMARY_KEY_IS_NULL:
1088
 
                return(ER_PRIMARY_CANT_HAVE_NULL);
1089
 
 
1090
 
        case DB_TOO_MANY_CONCURRENT_TRXS:
1091
 
 
1092
 
                /* Once MySQL add the appropriate code to errmsg.txt then
1093
 
                we can get rid of this #ifdef. NOTE: The code checked by
1094
 
                the #ifdef is the suggested name for the error condition
1095
 
                and the actual error code name could very well be different.
1096
 
                This will require some monitoring, ie. the status
1097
 
                of this request on our part.*/
 
1039
    return(HA_ERR_LOCK_WAIT_TIMEOUT);
 
1040
 
 
1041
  case DB_NO_REFERENCED_ROW:
 
1042
    return(HA_ERR_NO_REFERENCED_ROW);
 
1043
 
 
1044
  case DB_ROW_IS_REFERENCED:
 
1045
    return(HA_ERR_ROW_IS_REFERENCED);
 
1046
 
 
1047
  case DB_CANNOT_ADD_CONSTRAINT:
 
1048
    return(HA_ERR_CANNOT_ADD_FOREIGN);
 
1049
 
 
1050
  case DB_CANNOT_DROP_CONSTRAINT:
 
1051
 
 
1052
    return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
 
1053
            misleading, a new MySQL error
 
1054
            code should be introduced */
 
1055
 
 
1056
  case DB_COL_APPEARS_TWICE_IN_INDEX:
 
1057
  case DB_CORRUPTION:
 
1058
    return(HA_ERR_CRASHED);
 
1059
 
 
1060
  case DB_OUT_OF_FILE_SPACE:
 
1061
    return(HA_ERR_RECORD_FILE_FULL);
 
1062
 
 
1063
  case DB_TABLE_IS_BEING_USED:
 
1064
    return(HA_ERR_WRONG_COMMAND);
 
1065
 
 
1066
  case DB_TABLE_NOT_FOUND:
 
1067
    return(HA_ERR_NO_SUCH_TABLE);
 
1068
 
 
1069
  case DB_TOO_BIG_RECORD:
 
1070
    my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
 
1071
       page_get_free_space_of_empty(flags
 
1072
                  & DICT_TF_COMPACT) / 2);
 
1073
    return(HA_ERR_TO_BIG_ROW);
 
1074
 
 
1075
  case DB_NO_SAVEPOINT:
 
1076
    return(HA_ERR_NO_SAVEPOINT);
 
1077
 
 
1078
  case DB_LOCK_TABLE_FULL:
 
1079
    /* Since we rolled back the whole transaction, we must
 
1080
    tell it also to MySQL so that MySQL knows to empty the
 
1081
    cached binlog for this transaction */
 
1082
 
 
1083
    session_mark_transaction_to_rollback(session, TRUE);
 
1084
 
 
1085
    return(HA_ERR_LOCK_TABLE_FULL);
 
1086
 
 
1087
  case DB_PRIMARY_KEY_IS_NULL:
 
1088
    return(ER_PRIMARY_CANT_HAVE_NULL);
 
1089
 
 
1090
  case DB_TOO_MANY_CONCURRENT_TRXS:
 
1091
 
 
1092
    /* Once MySQL add the appropriate code to errmsg.txt then
 
1093
    we can get rid of this #ifdef. NOTE: The code checked by
 
1094
    the #ifdef is the suggested name for the error condition
 
1095
    and the actual error code name could very well be different.
 
1096
    This will require some monitoring, ie. the status
 
1097
    of this request on our part.*/
1098
1098
#ifdef ER_TOO_MANY_CONCURRENT_TRXS
1099
 
                return(ER_TOO_MANY_CONCURRENT_TRXS);
 
1099
    return(ER_TOO_MANY_CONCURRENT_TRXS);
1100
1100
#else
1101
 
                return(HA_ERR_RECORD_FILE_FULL);
 
1101
    return(HA_ERR_RECORD_FILE_FULL);
1102
1102
#endif
1103
 
        case DB_UNSUPPORTED:
1104
 
                return(HA_ERR_UNSUPPORTED);
1105
 
        }
 
1103
  case DB_UNSUPPORTED:
 
1104
    return(HA_ERR_UNSUPPORTED);
 
1105
  }
1106
1106
}
1107
1107
 
1108
1108
/*************************************************************//**
1121
1121
innobase_mysql_prepare_print_arbitrary_thd(void)
1122
1122
/*============================================*/
1123
1123
{
1124
 
        ut_ad(!mutex_own(&kernel_mutex));
1125
 
        pthread_mutex_lock(&LOCK_thread_count);
 
1124
  ut_ad(!mutex_own(&kernel_mutex));
 
1125
  pthread_mutex_lock(&LOCK_thread_count);
1126
1126
}
1127
1127
 
1128
1128
/*************************************************************//**
1139
1139
innobase_mysql_end_print_arbitrary_thd(void)
1140
1140
/*========================================*/
1141
1141
{
1142
 
        ut_ad(!mutex_own(&kernel_mutex));
1143
 
        pthread_mutex_unlock(&LOCK_thread_count);
 
1142
  ut_ad(!mutex_own(&kernel_mutex));
 
1143
  pthread_mutex_unlock(&LOCK_thread_count);
1144
1144
}
1145
1145
 
1146
1146
/*************************************************************//**
1149
1149
void
1150
1150
innobase_mysql_print_thd(
1151
1151
/*=====================*/
1152
 
        FILE*   f,              /*!< in: output stream */
1153
 
        void * in_session,      /*!< in: pointer to a Drizzle Session object */
1154
 
        uint    )               /*!< in: max query length to print, or 0 to
1155
 
                                   use the default max length */
 
1152
  FILE* f,    /*!< in: output stream */
 
1153
  void * in_session,  /*!< in: pointer to a Drizzle Session object */
 
1154
  uint  )   /*!< in: max query length to print, or 0 to
 
1155
           use the default max length */
1156
1156
{
1157
1157
  Session *session= reinterpret_cast<Session *>(in_session);
1158
1158
  fprintf(f,
1166
1166
  fprintf(f,
1167
1167
          "\n%s", session->getQueryString().c_str()
1168
1168
  );
1169
 
        putc('\n', f);
 
1169
  putc('\n', f);
1170
1170
}
1171
1171
 
1172
1172
/******************************************************************//**
1175
1175
void
1176
1176
innobase_get_cset_width(
1177
1177
/*====================*/
1178
 
        ulint   cset,           /*!< in: MySQL charset-collation code */
1179
 
        ulint*  mbminlen,       /*!< out: minimum length of a char (in bytes) */
1180
 
        ulint*  mbmaxlen)       /*!< out: maximum length of a char (in bytes) */
 
1178
  ulint cset,   /*!< in: MySQL charset-collation code */
 
1179
  ulint*  mbminlen, /*!< out: minimum length of a char (in bytes) */
 
1180
  ulint*  mbmaxlen) /*!< out: maximum length of a char (in bytes) */
1181
1181
{
1182
 
        CHARSET_INFO*   cs;
1183
 
        ut_ad(cset < 256);
1184
 
        ut_ad(mbminlen);
1185
 
        ut_ad(mbmaxlen);
 
1182
  CHARSET_INFO* cs;
 
1183
  ut_ad(cset < 256);
 
1184
  ut_ad(mbminlen);
 
1185
  ut_ad(mbmaxlen);
1186
1186
 
1187
 
        cs = all_charsets[cset];
1188
 
        if (cs) {
1189
 
                *mbminlen = cs->mbminlen;
1190
 
                *mbmaxlen = cs->mbmaxlen;
1191
 
        } else {
1192
 
                ut_a(cset == 0);
1193
 
                *mbminlen = *mbmaxlen = 0;
1194
 
        }
 
1187
  cs = all_charsets[cset];
 
1188
  if (cs) {
 
1189
    *mbminlen = cs->mbminlen;
 
1190
    *mbmaxlen = cs->mbmaxlen;
 
1191
  } else {
 
1192
    ut_a(cset == 0);
 
1193
    *mbminlen = *mbmaxlen = 0;
 
1194
  }
1195
1195
}
1196
1196
 
1197
1197
/******************************************************************//**
1200
1200
void
1201
1201
innobase_convert_from_table_id(
1202
1202
/*===========================*/
1203
 
        const void*,                    /*!< in: the 'from' character set */
1204
 
        char*                   to,     /*!< out: converted identifier */
1205
 
        const char*             from,   /*!< in: identifier to convert */
1206
 
        ulint                   len)    /*!< in: length of 'to', in bytes */
 
1203
  const void*,      /*!< in: the 'from' character set */
 
1204
  char*     to, /*!< out: converted identifier */
 
1205
  const char*   from, /*!< in: identifier to convert */
 
1206
  ulint     len)  /*!< in: length of 'to', in bytes */
1207
1207
{
1208
 
        strncpy(to, from, len);
 
1208
  strncpy(to, from, len);
1209
1209
}
1210
1210
 
1211
1211
/******************************************************************//**
1214
1214
void
1215
1215
innobase_convert_from_id(
1216
1216
/*=====================*/
1217
 
        const void*,                    /*!< in: the 'from' character set */
1218
 
        char*                   to,     /*!< out: converted identifier */
1219
 
        const char*             from,   /*!< in: identifier to convert */
1220
 
        ulint                   len)    /*!< in: length of 'to', in bytes */
 
1217
  const void*,      /*!< in: the 'from' character set */
 
1218
  char*     to, /*!< out: converted identifier */
 
1219
  const char*   from, /*!< in: identifier to convert */
 
1220
  ulint     len)  /*!< in: length of 'to', in bytes */
1221
1221
{
1222
 
        strncpy(to, from, len);
 
1222
  strncpy(to, from, len);
1223
1223
}
1224
1224
 
1225
1225
/******************************************************************//**
1226
1226
Compares NUL-terminated UTF-8 strings case insensitively.
1227
 
@return 0 if a=b, <0 if a<b, >1 if a>b */
 
1227
@return 0 if a=b, <0 if a<b, >1 if a>b */
1228
1228
extern "C" UNIV_INTERN
1229
1229
int
1230
1230
innobase_strcasecmp(
1231
1231
/*================*/
1232
 
        const char*     a,      /*!< in: first string to compare */
1233
 
        const char*     b)      /*!< in: second string to compare */
 
1232
  const char* a,  /*!< in: first string to compare */
 
1233
  const char* b)  /*!< in: second string to compare */
1234
1234
{
1235
 
        return(my_strcasecmp(system_charset_info, a, b));
 
1235
  return(my_strcasecmp(system_charset_info, a, b));
1236
1236
}
1237
1237
 
1238
1238
/******************************************************************//**
1241
1241
void
1242
1242
innobase_casedn_str(
1243
1243
/*================*/
1244
 
        char*   a)      /*!< in/out: string to put in lower case */
 
1244
  char* a)  /*!< in/out: string to put in lower case */
1245
1245
{
1246
 
        my_casedn_str(system_charset_info, a);
 
1246
  my_casedn_str(system_charset_info, a);
1247
1247
}
1248
1248
 
1249
1249
/**********************************************************************//**
1250
1250
Determines the connection character set.
1251
 
@return connection character set */
 
1251
@return connection character set */
1252
1252
extern "C" UNIV_INTERN
1253
1253
const void*
1254
1254
innobase_get_charset(
1255
1255
/*=================*/
1256
 
        void*   mysql_session)  /*!< in: MySQL thread handle */
 
1256
  void* mysql_session)  /*!< in: MySQL thread handle */
1257
1257
{
1258
 
        return session_charset(static_cast<Session*>(mysql_session));
 
1258
  return session_charset(static_cast<Session*>(mysql_session));
1259
1259
}
1260
1260
 
1261
1261
extern "C" UNIV_INTERN
1262
1262
bool
1263
1263
innobase_isspace(
1264
 
        const void *cs,
1265
 
        char char_to_test)
 
1264
  const void *cs,
 
1265
  char char_to_test)
1266
1266
{
1267
 
        return my_isspace(static_cast<const CHARSET_INFO *>(cs), char_to_test);
 
1267
  return my_isspace(static_cast<const CHARSET_INFO *>(cs), char_to_test);
1268
1268
}
1269
1269
 
1270
1270
UNIV_INTERN
1272
1272
innobase_fast_mutex_init(
1273
1273
        os_fast_mutex_t*        fast_mutex)
1274
1274
{
1275
 
        return pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
 
1275
  return pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST);
1276
1276
}
1277
1277
 
1278
1278
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
1282
1282
extern "C"
1283
1283
void __cdecl
1284
1284
_dosmaperr(
1285
 
        unsigned long); /*!< in: OS error value */
 
1285
  unsigned long); /*!< in: OS error value */
1286
1286
 
1287
1287
/*********************************************************************//**
1288
1288
Creates a temporary file.
1289
 
@return temporary file descriptor, or < 0 on error */
 
1289
@return temporary file descriptor, or < 0 on error */
1290
1290
extern "C" UNIV_INTERN
1291
1291
int
1292
1292
innobase_mysql_tmpfile(void)
1293
1293
/*========================*/
1294
1294
{
1295
 
        int     fd;                             /* handle of opened file */
1296
 
        HANDLE  osfh;                           /* OS handle of opened file */
1297
 
        char*   tmpdir;                         /* point to the directory
1298
 
                                                where to create file */
1299
 
        TCHAR   path_buf[MAX_PATH - 14];        /* buffer for tmp file path.
1300
 
                                                The length cannot be longer
1301
 
                                                than MAX_PATH - 14, or
1302
 
                                                GetTempFileName will fail. */
1303
 
        char    filename[MAX_PATH];             /* name of the tmpfile */
1304
 
        DWORD   fileaccess = GENERIC_READ       /* OS file access */
1305
 
                             | GENERIC_WRITE
1306
 
                             | DELETE;
1307
 
        DWORD   fileshare = FILE_SHARE_READ     /* OS file sharing mode */
1308
 
                            | FILE_SHARE_WRITE
1309
 
                            | FILE_SHARE_DELETE;
1310
 
        DWORD   filecreate = CREATE_ALWAYS;     /* OS method of open/create */
1311
 
        DWORD   fileattrib =                    /* OS file attribute flags */
1312
 
                             FILE_ATTRIBUTE_NORMAL
1313
 
                             | FILE_FLAG_DELETE_ON_CLOSE
1314
 
                             | FILE_ATTRIBUTE_TEMPORARY
1315
 
                             | FILE_FLAG_SEQUENTIAL_SCAN;
1316
 
 
1317
 
        tmpdir = my_tmpdir(&mysql_tmpdir_list);
1318
 
 
1319
 
        /* The tmpdir parameter can not be NULL for GetTempFileName. */
1320
 
        if (!tmpdir) {
1321
 
                uint    ret;
1322
 
 
1323
 
                /* Use GetTempPath to determine path for temporary files. */
1324
 
                ret = GetTempPath(sizeof(path_buf), path_buf);
1325
 
                if (ret > sizeof(path_buf) || (ret == 0)) {
1326
 
 
1327
 
                        _dosmaperr(GetLastError());     /* map error */
1328
 
                        return(-1);
1329
 
                }
1330
 
 
1331
 
                tmpdir = path_buf;
1332
 
        }
1333
 
 
1334
 
        /* Use GetTempFileName to generate a unique filename. */
1335
 
        if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
1336
 
 
1337
 
                _dosmaperr(GetLastError());     /* map error */
1338
 
                return(-1);
1339
 
        }
1340
 
 
1341
 
        /* Open/Create the file. */
1342
 
        osfh = CreateFile(filename, fileaccess, fileshare, NULL,
1343
 
                          filecreate, fileattrib, NULL);
1344
 
        if (osfh == INVALID_HANDLE_VALUE) {
1345
 
 
1346
 
                /* open/create file failed! */
1347
 
                _dosmaperr(GetLastError());     /* map error */
1348
 
                return(-1);
1349
 
        }
1350
 
 
1351
 
        do {
1352
 
                /* Associates a CRT file descriptor with the OS file handle. */
1353
 
                fd = _open_osfhandle((intptr_t) osfh, 0);
1354
 
        } while (fd == -1 && errno == EINTR);
1355
 
 
1356
 
        if (fd == -1) {
1357
 
                /* Open failed, close the file handle. */
1358
 
 
1359
 
                _dosmaperr(GetLastError());     /* map error */
1360
 
                CloseHandle(osfh);              /* no need to check if
1361
 
                                                CloseHandle fails */
1362
 
        }
1363
 
 
1364
 
        return(fd);
 
1295
  int fd;       /* handle of opened file */
 
1296
  HANDLE  osfh;       /* OS handle of opened file */
 
1297
  char* tmpdir;       /* point to the directory
 
1298
            where to create file */
 
1299
  TCHAR path_buf[MAX_PATH - 14];  /* buffer for tmp file path.
 
1300
            The length cannot be longer
 
1301
            than MAX_PATH - 14, or
 
1302
            GetTempFileName will fail. */
 
1303
  char  filename[MAX_PATH];   /* name of the tmpfile */
 
1304
  DWORD fileaccess = GENERIC_READ /* OS file access */
 
1305
           | GENERIC_WRITE
 
1306
           | DELETE;
 
1307
  DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
 
1308
          | FILE_SHARE_WRITE
 
1309
          | FILE_SHARE_DELETE;
 
1310
  DWORD filecreate = CREATE_ALWAYS; /* OS method of open/create */
 
1311
  DWORD fileattrib =      /* OS file attribute flags */
 
1312
           FILE_ATTRIBUTE_NORMAL
 
1313
           | FILE_FLAG_DELETE_ON_CLOSE
 
1314
           | FILE_ATTRIBUTE_TEMPORARY
 
1315
           | FILE_FLAG_SEQUENTIAL_SCAN;
 
1316
 
 
1317
  tmpdir = my_tmpdir(&mysql_tmpdir_list);
 
1318
 
 
1319
  /* The tmpdir parameter can not be NULL for GetTempFileName. */
 
1320
  if (!tmpdir) {
 
1321
    uint  ret;
 
1322
 
 
1323
    /* Use GetTempPath to determine path for temporary files. */
 
1324
    ret = GetTempPath(sizeof(path_buf), path_buf);
 
1325
    if (ret > sizeof(path_buf) || (ret == 0)) {
 
1326
 
 
1327
      _dosmaperr(GetLastError()); /* map error */
 
1328
      return(-1);
 
1329
    }
 
1330
 
 
1331
    tmpdir = path_buf;
 
1332
  }
 
1333
 
 
1334
  /* Use GetTempFileName to generate a unique filename. */
 
1335
  if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
 
1336
 
 
1337
    _dosmaperr(GetLastError()); /* map error */
 
1338
    return(-1);
 
1339
  }
 
1340
 
 
1341
  /* Open/Create the file. */
 
1342
  osfh = CreateFile(filename, fileaccess, fileshare, NULL,
 
1343
        filecreate, fileattrib, NULL);
 
1344
  if (osfh == INVALID_HANDLE_VALUE) {
 
1345
 
 
1346
    /* open/create file failed! */
 
1347
    _dosmaperr(GetLastError()); /* map error */
 
1348
    return(-1);
 
1349
  }
 
1350
 
 
1351
  do {
 
1352
    /* Associates a CRT file descriptor with the OS file handle. */
 
1353
    fd = _open_osfhandle((intptr_t) osfh, 0);
 
1354
  } while (fd == -1 && errno == EINTR);
 
1355
 
 
1356
  if (fd == -1) {
 
1357
    /* Open failed, close the file handle. */
 
1358
 
 
1359
    _dosmaperr(GetLastError()); /* map error */
 
1360
    CloseHandle(osfh);    /* no need to check if
 
1361
            CloseHandle fails */
 
1362
  }
 
1363
 
 
1364
  return(fd);
1365
1365
}
1366
1366
#else
1367
1367
/*********************************************************************//**
1368
1368
Creates a temporary file.
1369
 
@return temporary file descriptor, or < 0 on error */
 
1369
@return temporary file descriptor, or < 0 on error */
1370
1370
extern "C" UNIV_INTERN
1371
1371
int
1372
1372
innobase_mysql_tmpfile(void)
1373
1373
/*========================*/
1374
1374
{
1375
 
        int     fd2 = -1;
1376
 
        int     fd = mysql_tmpfile("ib");
1377
 
        if (fd >= 0) {
1378
 
                /* Copy the file descriptor, so that the additional resources
1379
 
                allocated by create_temp_file() can be freed by invoking
1380
 
                internal::my_close().
 
1375
  int fd2 = -1;
 
1376
  int fd = mysql_tmpfile("ib");
 
1377
  if (fd >= 0) {
 
1378
    /* Copy the file descriptor, so that the additional resources
 
1379
    allocated by create_temp_file() can be freed by invoking
 
1380
    internal::my_close().
1381
1381
 
1382
 
                Because the file descriptor returned by this function
1383
 
                will be passed to fdopen(), it will be closed by invoking
1384
 
                fclose(), which in turn will invoke close() instead of
1385
 
                internal::my_close(). */
1386
 
                fd2 = dup(fd);
1387
 
                if (fd2 < 0) {
1388
 
                        errno=errno;
1389
 
                        my_error(EE_OUT_OF_FILERESOURCES,
1390
 
                                 MYF(ME_BELL+ME_WAITTANG),
1391
 
                                 "ib*", errno);
1392
 
                }
1393
 
                internal::my_close(fd, MYF(MY_WME));
1394
 
        }
1395
 
        return(fd2);
 
1382
    Because the file descriptor returned by this function
 
1383
    will be passed to fdopen(), it will be closed by invoking
 
1384
    fclose(), which in turn will invoke close() instead of
 
1385
    internal::my_close(). */
 
1386
    fd2 = dup(fd);
 
1387
    if (fd2 < 0) {
 
1388
      errno=errno;
 
1389
      my_error(EE_OUT_OF_FILERESOURCES,
 
1390
         MYF(ME_BELL+ME_WAITTANG),
 
1391
         "ib*", errno);
 
1392
    }
 
1393
    internal::my_close(fd, MYF(MY_WME));
 
1394
  }
 
1395
  return(fd2);
1396
1396
}
1397
1397
#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
1398
1398
 
1405
1405
The result is always NUL-terminated (provided buf_size > 0) and the
1406
1406
number of bytes that were written to "buf" is returned (including the
1407
1407
terminating NUL).
1408
 
@return number of bytes that were written */
 
1408
@return number of bytes that were written */
1409
1409
extern "C" UNIV_INTERN
1410
1410
ulint
1411
1411
innobase_raw_format(
1412
1412
/*================*/
1413
 
        const char*     data,           /*!< in: raw data */
1414
 
        ulint           data_len,       /*!< in: raw data length
1415
 
                                        in bytes */
1416
 
        ulint           ,               /*!< in: charset collation */
1417
 
        char*           buf,            /*!< out: output buffer */
1418
 
        ulint           buf_size)       /*!< in: output buffer size
1419
 
                                        in bytes */
 
1413
  const char* data,   /*!< in: raw data */
 
1414
  ulint   data_len, /*!< in: raw data length
 
1415
          in bytes */
 
1416
  ulint   ,   /*!< in: charset collation */
 
1417
  char*   buf,    /*!< out: output buffer */
 
1418
  ulint   buf_size) /*!< in: output buffer size
 
1419
          in bytes */
1420
1420
{
1421
 
        return(ut_str_sql_format(data, data_len, buf, buf_size));
 
1421
  return(ut_str_sql_format(data, data_len, buf, buf_size));
1422
1422
}
1423
1423
 
1424
1424
/*********************************************************************//**
1433
1433
Note: This function is also called with increment set to the number of
1434
1434
values we want to reserve for multi-value inserts e.g.,
1435
1435
 
1436
 
        INSERT INTO T VALUES(), (), ();
 
1436
  INSERT INTO T VALUES(), (), ();
1437
1437
 
1438
1438
innobase_next_autoinc() will be called with increment set to
1439
1439
n * 3 where autoinc_lock_mode != TRADITIONAL because we want
1440
1440
to reserve 3 values for the multi-value INSERT above.
1441
 
@return the next value */
 
1441
@return the next value */
1442
1442
static
1443
1443
uint64_t
1444
1444
innobase_next_autoinc(
1445
1445
/*==================*/
1446
 
        uint64_t        current,        /*!< in: Current value */
1447
 
        uint64_t        increment,      /*!< in: increment current by */
1448
 
        uint64_t        offset,         /*!< in: AUTOINC offset */
1449
 
        uint64_t        max_value)      /*!< in: max value for type */
 
1446
  uint64_t  current,  /*!< in: Current value */
 
1447
  uint64_t  increment,  /*!< in: increment current by */
 
1448
  uint64_t  offset,   /*!< in: AUTOINC offset */
 
1449
  uint64_t  max_value)  /*!< in: max value for type */
1450
1450
{
1451
 
        uint64_t        next_value;
1452
 
 
1453
 
        /* Should never be 0. */
1454
 
        ut_a(increment > 0);
1455
 
 
1456
 
        /* According to MySQL documentation, if the offset is greater than
1457
 
        the increment then the offset is ignored. */
1458
 
        if (offset > increment) {
1459
 
                offset = 0;
1460
 
        }
1461
 
 
1462
 
        if (max_value <= current) {
1463
 
                next_value = max_value;
1464
 
        } else if (offset <= 1) {
1465
 
                /* Offset 0 and 1 are the same, because there must be at
1466
 
                least one node in the system. */
1467
 
                if (max_value - current <= increment) {
1468
 
                        next_value = max_value;
1469
 
                } else {
1470
 
                        next_value = current + increment;
1471
 
                }
1472
 
        } else if (max_value > current) {
1473
 
                if (current > offset) {
1474
 
                        next_value = ((current - offset) / increment) + 1;
1475
 
                } else {
1476
 
                        next_value = ((offset - current) / increment) + 1;
1477
 
                }
1478
 
 
1479
 
                ut_a(increment > 0);
1480
 
                ut_a(next_value > 0);
1481
 
 
1482
 
                /* Check for multiplication overflow. */
1483
 
                if (increment > (max_value / next_value)) {
1484
 
 
1485
 
                        next_value = max_value;
1486
 
                } else {
1487
 
                        next_value *= increment;
1488
 
 
1489
 
                        ut_a(max_value >= next_value);
1490
 
 
1491
 
                        /* Check for overflow. */
1492
 
                        if (max_value - next_value <= offset) {
1493
 
                                next_value = max_value;
1494
 
                        } else {
1495
 
                                next_value += offset;
1496
 
                        }
1497
 
                }
1498
 
        } else {
1499
 
                next_value = max_value;
1500
 
        }
1501
 
 
1502
 
        ut_a(next_value <= max_value);
1503
 
 
1504
 
        return(next_value);
 
1451
  uint64_t  next_value;
 
1452
 
 
1453
  /* Should never be 0. */
 
1454
  ut_a(increment > 0);
 
1455
 
 
1456
  /* According to MySQL documentation, if the offset is greater than
 
1457
  the increment then the offset is ignored. */
 
1458
  if (offset > increment) {
 
1459
    offset = 0;
 
1460
  }
 
1461
 
 
1462
  if (max_value <= current) {
 
1463
    next_value = max_value;
 
1464
  } else if (offset <= 1) {
 
1465
    /* Offset 0 and 1 are the same, because there must be at
 
1466
    least one node in the system. */
 
1467
    if (max_value - current <= increment) {
 
1468
      next_value = max_value;
 
1469
    } else {
 
1470
      next_value = current + increment;
 
1471
    }
 
1472
  } else if (max_value > current) {
 
1473
    if (current > offset) {
 
1474
      next_value = ((current - offset) / increment) + 1;
 
1475
    } else {
 
1476
      next_value = ((offset - current) / increment) + 1;
 
1477
    }
 
1478
 
 
1479
    ut_a(increment > 0);
 
1480
    ut_a(next_value > 0);
 
1481
 
 
1482
    /* Check for multiplication overflow. */
 
1483
    if (increment > (max_value / next_value)) {
 
1484
 
 
1485
      next_value = max_value;
 
1486
    } else {
 
1487
      next_value *= increment;
 
1488
 
 
1489
      ut_a(max_value >= next_value);
 
1490
 
 
1491
      /* Check for overflow. */
 
1492
      if (max_value - next_value <= offset) {
 
1493
        next_value = max_value;
 
1494
      } else {
 
1495
        next_value += offset;
 
1496
      }
 
1497
    }
 
1498
  } else {
 
1499
    next_value = max_value;
 
1500
  }
 
1501
 
 
1502
  ut_a(next_value <= max_value);
 
1503
 
 
1504
  return(next_value);
1505
1505
}
1506
1506
 
1507
1507
/*********************************************************************//**
1510
1510
void
1511
1511
innobase_trx_init(
1512
1512
/*==============*/
1513
 
        Session*        session,        /*!< in: user thread handle */
1514
 
        trx_t*  trx)    /*!< in/out: InnoDB transaction handle */
 
1513
  Session*  session,  /*!< in: user thread handle */
 
1514
  trx_t*  trx)  /*!< in/out: InnoDB transaction handle */
1515
1515
{
1516
 
        assert(session == trx->mysql_thd);
1517
 
 
1518
 
        trx->check_foreigns = !session_test_options(
1519
 
                session, OPTION_NO_FOREIGN_KEY_CHECKS);
1520
 
 
1521
 
        trx->check_unique_secondary = !session_test_options(
1522
 
                session, OPTION_RELAXED_UNIQUE_CHECKS);
1523
 
 
1524
 
        return;
 
1516
  assert(session == trx->mysql_thd);
 
1517
 
 
1518
  trx->check_foreigns = !session_test_options(
 
1519
    session, OPTION_NO_FOREIGN_KEY_CHECKS);
 
1520
 
 
1521
  trx->check_unique_secondary = !session_test_options(
 
1522
    session, OPTION_RELAXED_UNIQUE_CHECKS);
 
1523
 
 
1524
  return;
1525
1525
}
1526
1526
 
1527
1527
/*********************************************************************//**
1528
1528
Allocates an InnoDB transaction for a MySQL Cursor object.
1529
 
@return InnoDB transaction handle */
 
1529
@return InnoDB transaction handle */
1530
1530
extern "C" UNIV_INTERN
1531
1531
trx_t*
1532
1532
innobase_trx_allocate(
1533
1533
/*==================*/
1534
 
        Session*        session)        /*!< in: user thread handle */
 
1534
  Session*  session)  /*!< in: user thread handle */
1535
1535
{
1536
 
        trx_t*  trx;
1537
 
 
1538
 
        assert(session != NULL);
1539
 
        assert(EQ_CURRENT_SESSION(session));
1540
 
 
1541
 
        trx = trx_allocate_for_mysql();
1542
 
 
1543
 
        trx->mysql_thd = session;
1544
 
        trx->mysql_query_str = session->query.c_str();
1545
 
 
1546
 
        innobase_trx_init(session, trx);
1547
 
 
1548
 
        return(trx);
 
1536
  trx_t*  trx;
 
1537
 
 
1538
  assert(session != NULL);
 
1539
  assert(EQ_CURRENT_SESSION(session));
 
1540
 
 
1541
  trx = trx_allocate_for_mysql();
 
1542
 
 
1543
  trx->mysql_thd = session;
 
1544
  trx->mysql_query_str = session->query.c_str();
 
1545
 
 
1546
  innobase_trx_init(session, trx);
 
1547
 
 
1548
  return(trx);
1549
1549
}
1550
1550
 
1551
1551
/*********************************************************************//**
1552
1552
Gets the InnoDB transaction handle for a MySQL Cursor object, creates
1553
1553
an InnoDB transaction struct if the corresponding MySQL thread struct still
1554
1554
lacks one.
1555
 
@return InnoDB transaction handle */
 
1555
@return InnoDB transaction handle */
1556
1556
static
1557
1557
trx_t*
1558
1558
check_trx_exists(
1559
1559
/*=============*/
1560
 
        Session*        session)        /*!< in: user thread handle */
 
1560
  Session*  session)  /*!< in: user thread handle */
1561
1561
{
1562
 
        trx_t*& trx = session_to_trx(session);
1563
 
 
1564
 
        ut_ad(EQ_CURRENT_SESSION(session));
1565
 
 
1566
 
        if (trx == NULL) {
1567
 
                trx = innobase_trx_allocate(session);
1568
 
        } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
1569
 
                mem_analyze_corruption(trx);
1570
 
                ut_error;
1571
 
        }
1572
 
 
1573
 
        innobase_trx_init(session, trx);
1574
 
 
1575
 
        return(trx);
 
1562
  trx_t*& trx = session_to_trx(session);
 
1563
 
 
1564
  ut_ad(EQ_CURRENT_SESSION(session));
 
1565
 
 
1566
  if (trx == NULL) {
 
1567
    trx = innobase_trx_allocate(session);
 
1568
  } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
 
1569
    mem_analyze_corruption(trx);
 
1570
    ut_error;
 
1571
  }
 
1572
 
 
1573
  innobase_trx_init(session, trx);
 
1574
 
 
1575
  return(trx);
1576
1576
}
1577
1577
 
1578
1578
 
1605
1605
void
1606
1606
ha_innobase::update_session(
1607
1607
/*====================*/
1608
 
        Session*        session)        /*!< in: thd to use the handle */
 
1608
  Session*  session)  /*!< in: thd to use the handle */
1609
1609
{
1610
 
        trx_t*          trx;
1611
 
 
1612
 
        trx = check_trx_exists(session);
1613
 
 
1614
 
        if (prebuilt->trx != trx) {
1615
 
 
1616
 
                row_update_prebuilt_trx(prebuilt, trx);
1617
 
        }
1618
 
 
1619
 
        user_session = session;
 
1610
  trx_t*    trx;
 
1611
 
 
1612
  trx = check_trx_exists(session);
 
1613
 
 
1614
  if (prebuilt->trx != trx) {
 
1615
 
 
1616
    row_update_prebuilt_trx(prebuilt, trx);
 
1617
  }
 
1618
 
 
1619
  user_session = session;
1620
1620
}
1621
1621
 
1622
1622
/*********************************************************************//**
1628
1628
ha_innobase::update_session()
1629
1629
/*=====================*/
1630
1630
{
1631
 
        Session*        session = ha_session();
1632
 
        ut_ad(EQ_CURRENT_SESSION(session));
1633
 
        update_session(session);
 
1631
  Session*  session = ha_session();
 
1632
  ut_ad(EQ_CURRENT_SESSION(session));
 
1633
  update_session(session);
1634
1634
}
1635
1635
 
1636
1636
/*****************************************************************//**
1637
1637
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
1638
1638
and quote it if needed.
1639
 
@return pointer to the end of buf */
 
1639
@return pointer to the end of buf */
1640
1640
static
1641
1641
char*
1642
1642
innobase_convert_identifier(
1643
1643
/*========================*/
1644
 
        char*           buf,    /*!< out: buffer for converted identifier */
1645
 
        ulint           buflen, /*!< in: length of buf, in bytes */
1646
 
        const char*     id,     /*!< in: identifier to convert */
1647
 
        ulint           idlen,  /*!< in: length of id, in bytes */
1648
 
        void*           session,/*!< in: MySQL connection thread, or NULL */
1649
 
        ibool           file_id)/*!< in: TRUE=id is a table or database name;
1650
 
                                FALSE=id is an UTF-8 string */
 
1644
  char*   buf,  /*!< out: buffer for converted identifier */
 
1645
  ulint   buflen, /*!< in: length of buf, in bytes */
 
1646
  const char* id, /*!< in: identifier to convert */
 
1647
  ulint   idlen,  /*!< in: length of id, in bytes */
 
1648
  void*   session,/*!< in: MySQL connection thread, or NULL */
 
1649
  ibool   file_id)/*!< in: TRUE=id is a table or database name;
 
1650
        FALSE=id is an UTF-8 string */
1651
1651
{
1652
 
        char nz[NAME_LEN + 1];
1653
 
        char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
1654
 
 
1655
 
        const char*     s       = id;
1656
 
        int             q;
1657
 
 
1658
 
        if (file_id) {
1659
 
                /* Decode the table name.  The filename_to_tablename()
1660
 
                function expects a NUL-terminated string.  The input and
1661
 
                output strings buffers must not be shared. */
1662
 
 
1663
 
                if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
1664
 
                        idlen = (sizeof nz) - 1;
1665
 
                }
1666
 
 
1667
 
                memcpy(nz, id, idlen);
1668
 
                nz[idlen] = 0;
1669
 
 
1670
 
                s = nz2;
1671
 
                idlen = filename_to_tablename(nz, nz2, sizeof nz2);
1672
 
        }
1673
 
 
1674
 
        /* See if the identifier needs to be quoted. */
1675
 
        if (UNIV_UNLIKELY(!session)) {
1676
 
                q = '"';
1677
 
        } else {
1678
 
                q = get_quote_char_for_identifier();
1679
 
        }
1680
 
 
1681
 
        if (q == EOF) {
1682
 
                if (UNIV_UNLIKELY(idlen > buflen)) {
1683
 
                        idlen = buflen;
1684
 
                }
1685
 
                memcpy(buf, s, idlen);
1686
 
                return(buf + idlen);
1687
 
        }
1688
 
 
1689
 
        /* Quote the identifier. */
1690
 
        if (buflen < 2) {
1691
 
                return(buf);
1692
 
        }
1693
 
 
1694
 
        *buf++ = q;
1695
 
        buflen--;
1696
 
 
1697
 
        for (; idlen; idlen--) {
1698
 
                int     c = *s++;
1699
 
                if (UNIV_UNLIKELY(c == q)) {
1700
 
                        if (UNIV_UNLIKELY(buflen < 3)) {
1701
 
                                break;
1702
 
                        }
1703
 
 
1704
 
                        *buf++ = c;
1705
 
                        *buf++ = c;
1706
 
                        buflen -= 2;
1707
 
                } else {
1708
 
                        if (UNIV_UNLIKELY(buflen < 2)) {
1709
 
                                break;
1710
 
                        }
1711
 
 
1712
 
                        *buf++ = c;
1713
 
                        buflen--;
1714
 
                }
1715
 
        }
1716
 
 
1717
 
        *buf++ = q;
1718
 
        return(buf);
 
1652
  char nz[NAME_LEN + 1];
 
1653
  char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
 
1654
 
 
1655
  const char* s = id;
 
1656
  int   q;
 
1657
 
 
1658
  if (file_id) {
 
1659
    /* Decode the table name.  The filename_to_tablename()
 
1660
    function expects a NUL-terminated string.  The input and
 
1661
    output strings buffers must not be shared. */
 
1662
 
 
1663
    if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
 
1664
      idlen = (sizeof nz) - 1;
 
1665
    }
 
1666
 
 
1667
    memcpy(nz, id, idlen);
 
1668
    nz[idlen] = 0;
 
1669
 
 
1670
    s = nz2;
 
1671
    idlen = filename_to_tablename(nz, nz2, sizeof nz2);
 
1672
  }
 
1673
 
 
1674
  /* See if the identifier needs to be quoted. */
 
1675
  if (UNIV_UNLIKELY(!session)) {
 
1676
    q = '"';
 
1677
  } else {
 
1678
    q = get_quote_char_for_identifier();
 
1679
  }
 
1680
 
 
1681
  if (q == EOF) {
 
1682
    if (UNIV_UNLIKELY(idlen > buflen)) {
 
1683
      idlen = buflen;
 
1684
    }
 
1685
    memcpy(buf, s, idlen);
 
1686
    return(buf + idlen);
 
1687
  }
 
1688
 
 
1689
  /* Quote the identifier. */
 
1690
  if (buflen < 2) {
 
1691
    return(buf);
 
1692
  }
 
1693
 
 
1694
  *buf++ = q;
 
1695
  buflen--;
 
1696
 
 
1697
  for (; idlen; idlen--) {
 
1698
    int c = *s++;
 
1699
    if (UNIV_UNLIKELY(c == q)) {
 
1700
      if (UNIV_UNLIKELY(buflen < 3)) {
 
1701
        break;
 
1702
      }
 
1703
 
 
1704
      *buf++ = c;
 
1705
      *buf++ = c;
 
1706
      buflen -= 2;
 
1707
    } else {
 
1708
      if (UNIV_UNLIKELY(buflen < 2)) {
 
1709
        break;
 
1710
      }
 
1711
 
 
1712
      *buf++ = c;
 
1713
      buflen--;
 
1714
    }
 
1715
  }
 
1716
 
 
1717
  *buf++ = q;
 
1718
  return(buf);
1719
1719
}
1720
1720
 
1721
1721
/*****************************************************************//**
1722
1722
Convert a table or index name to the MySQL system_charset_info (UTF-8)
1723
1723
and quote it if needed.
1724
 
@return pointer to the end of buf */
 
1724
@return pointer to the end of buf */
1725
1725
extern "C" UNIV_INTERN
1726
1726
char*
1727
1727
innobase_convert_name(
1728
1728
/*==================*/
1729
 
        char*           buf,    /*!< out: buffer for converted identifier */
1730
 
        ulint           buflen, /*!< in: length of buf, in bytes */
1731
 
        const char*     id,     /*!< in: identifier to convert */
1732
 
        ulint           idlen,  /*!< in: length of id, in bytes */
1733
 
        void*           session,/*!< in: MySQL connection thread, or NULL */
1734
 
        ibool           table_id)/*!< in: TRUE=id is a table or database name;
1735
 
                                FALSE=id is an index name */
 
1729
  char*   buf,  /*!< out: buffer for converted identifier */
 
1730
  ulint   buflen, /*!< in: length of buf, in bytes */
 
1731
  const char* id, /*!< in: identifier to convert */
 
1732
  ulint   idlen,  /*!< in: length of id, in bytes */
 
1733
  void*   session,/*!< in: MySQL connection thread, or NULL */
 
1734
  ibool   table_id)/*!< in: TRUE=id is a table or database name;
 
1735
        FALSE=id is an index name */
1736
1736
{
1737
 
        char*           s       = buf;
1738
 
        const char*     bufend  = buf + buflen;
1739
 
 
1740
 
        if (table_id) {
1741
 
                const char*     slash = (const char*) memchr(id, '/', idlen);
1742
 
                if (!slash) {
1743
 
 
1744
 
                        goto no_db_name;
1745
 
                }
1746
 
 
1747
 
                /* Print the database name and table name separately. */
1748
 
                s = innobase_convert_identifier(s, bufend - s, id, slash - id,
1749
 
                                                session, TRUE);
1750
 
                if (UNIV_LIKELY(s < bufend)) {
1751
 
                        *s++ = '.';
1752
 
                        s = innobase_convert_identifier(s, bufend - s,
1753
 
                                                        slash + 1, idlen
1754
 
                                                        - (slash - id) - 1,
1755
 
                                                        session, TRUE);
1756
 
                }
1757
 
        } else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
1758
 
                /* Temporary index name (smart ALTER TABLE) */
1759
 
                const char temp_index_suffix[]= "--temporary--";
1760
 
 
1761
 
                s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
1762
 
                                                session, FALSE);
1763
 
                if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
1764
 
                        memcpy(s, temp_index_suffix,
1765
 
                               sizeof temp_index_suffix - 1);
1766
 
                        s += sizeof temp_index_suffix - 1;
1767
 
                }
1768
 
        } else {
 
1737
  char*   s = buf;
 
1738
  const char* bufend  = buf + buflen;
 
1739
 
 
1740
  if (table_id) {
 
1741
    const char* slash = (const char*) memchr(id, '/', idlen);
 
1742
    if (!slash) {
 
1743
 
 
1744
      goto no_db_name;
 
1745
    }
 
1746
 
 
1747
    /* Print the database name and table name separately. */
 
1748
    s = innobase_convert_identifier(s, bufend - s, id, slash - id,
 
1749
            session, TRUE);
 
1750
    if (UNIV_LIKELY(s < bufend)) {
 
1751
      *s++ = '.';
 
1752
      s = innobase_convert_identifier(s, bufend - s,
 
1753
              slash + 1, idlen
 
1754
              - (slash - id) - 1,
 
1755
              session, TRUE);
 
1756
    }
 
1757
  } else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
 
1758
    /* Temporary index name (smart ALTER TABLE) */
 
1759
    const char temp_index_suffix[]= "--temporary--";
 
1760
 
 
1761
    s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
 
1762
            session, FALSE);
 
1763
    if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
 
1764
      memcpy(s, temp_index_suffix,
 
1765
             sizeof temp_index_suffix - 1);
 
1766
      s += sizeof temp_index_suffix - 1;
 
1767
    }
 
1768
  } else {
1769
1769
no_db_name:
1770
 
                s = innobase_convert_identifier(buf, buflen, id, idlen,
1771
 
                                                session, table_id);
1772
 
        }
 
1770
    s = innobase_convert_identifier(buf, buflen, id, idlen,
 
1771
            session, table_id);
 
1772
  }
1773
1773
 
1774
 
        return(s);
 
1774
  return(s);
1775
1775
 
1776
1776
}
1777
1777
 
1778
1778
/**********************************************************************//**
1779
1779
Determines if the currently running transaction has been interrupted.
1780
 
@return TRUE if interrupted */
 
1780
@return TRUE if interrupted */
1781
1781
extern "C" UNIV_INTERN
1782
1782
ibool
1783
1783
trx_is_interrupted(
1784
1784
/*===============*/
1785
 
        trx_t*  trx)    /*!< in: transaction */
 
1785
  trx_t*  trx)  /*!< in: transaction */
1786
1786
{
1787
 
        return(trx && trx->mysql_thd && session_killed((Session*) trx->mysql_thd));
 
1787
  return(trx && trx->mysql_thd && session_killed((Session*) trx->mysql_thd));
1788
1788
}
1789
1789
 
1790
1790
/**************************************************************//**
1794
1794
void
1795
1795
reset_template(
1796
1796
/*===========*/
1797
 
        row_prebuilt_t* prebuilt)       /*!< in/out: prebuilt struct */
 
1797
  row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */
1798
1798
{
1799
 
        prebuilt->keep_other_fields_on_keyread = 0;
1800
 
        prebuilt->read_just_key = 0;
 
1799
  prebuilt->keep_other_fields_on_keyread = 0;
 
1800
  prebuilt->read_just_key = 0;
1801
1801
}
1802
1802
 
1803
1803
/*********************************************************************//**
1804
1804
Opens an InnoDB database.
1805
 
@return 0 on success, error code on failure */
 
1805
@return 0 on success, error code on failure */
1806
1806
static
1807
1807
int
1808
1808
innobase_init(
1809
1809
/*==========*/
1810
 
        plugin::Context &context)       /*!< in: Drizzle Plugin Context */
 
1810
  plugin::Context &context) /*!< in: Drizzle Plugin Context */
1811
1811
{
1812
 
        static char     current_dir[3];         /*!< Set if using current lib */
1813
 
        int             err;
1814
 
        bool            ret;
1815
 
        char            *default_path;
1816
 
        uint            format_id;
1817
 
 
1818
 
        innodb_engine_ptr= new InnobaseEngine(innobase_engine_name);
1819
 
 
1820
 
        ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
 
1812
  static char current_dir[3];   /*!< Set if using current lib */
 
1813
  int   err;
 
1814
  bool    ret;
 
1815
  char    *default_path;
 
1816
  uint    format_id;
 
1817
 
 
1818
  innodb_engine_ptr= new InnobaseEngine(innobase_engine_name);
 
1819
 
 
1820
  ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
1821
1821
 
1822
1822
#ifdef UNIV_DEBUG
1823
 
        static const char       test_filename[] = "-@";
1824
 
        char                    test_tablename[sizeof test_filename
1825
 
                                + sizeof srv_mysql50_table_name_prefix];
1826
 
        if ((sizeof test_tablename) - 1
1827
 
                        != filename_to_tablename(test_filename, test_tablename,
1828
 
                        sizeof test_tablename)
1829
 
                        || strncmp(test_tablename,
1830
 
                        srv_mysql50_table_name_prefix,
1831
 
                        sizeof srv_mysql50_table_name_prefix)
1832
 
                        || strcmp(test_tablename
1833
 
                        + sizeof srv_mysql50_table_name_prefix,
1834
 
                        test_filename)) {
1835
 
                errmsg_printf(ERRMSG_LVL_ERROR, "tablename encoding has been changed");
1836
 
                goto error;
1837
 
        }
 
1823
  static const char test_filename[] = "-@";
 
1824
  char      test_tablename[sizeof test_filename
 
1825
        + sizeof srv_mysql50_table_name_prefix];
 
1826
  if ((sizeof test_tablename) - 1
 
1827
      != filename_to_tablename(test_filename, test_tablename,
 
1828
      sizeof test_tablename)
 
1829
      || strncmp(test_tablename,
 
1830
      srv_mysql50_table_name_prefix,
 
1831
      sizeof srv_mysql50_table_name_prefix)
 
1832
      || strcmp(test_tablename
 
1833
      + sizeof srv_mysql50_table_name_prefix,
 
1834
      test_filename)) {
 
1835
    errmsg_printf(ERRMSG_LVL_ERROR, "tablename encoding has been changed");
 
1836
    goto error;
 
1837
  }
1838
1838
#endif /* UNIV_DEBUG */
1839
1839
 
1840
 
        /* Check that values don't overflow on 32-bit systems. */
1841
 
        if (sizeof(ulint) == 4) {
1842
 
                if (innobase_buffer_pool_size > UINT32_MAX) {
1843
 
                        errmsg_printf(ERRMSG_LVL_ERROR, 
1844
 
                                "innobase_buffer_pool_size can't be over 4GB"
1845
 
                                " on 32-bit systems");
1846
 
 
1847
 
                        goto error;
1848
 
                }
1849
 
 
1850
 
                if (innobase_log_file_size > UINT32_MAX) {
1851
 
                        errmsg_printf(ERRMSG_LVL_ERROR, 
1852
 
                                "innobase_log_file_size can't be over 4GB"
1853
 
                                " on 32-bit systems");
1854
 
 
1855
 
                        goto error;
1856
 
                }
1857
 
        }
1858
 
 
1859
 
        os_innodb_umask = (ulint)internal::my_umask;
1860
 
 
1861
 
        /* First calculate the default path for innodb_data_home_dir etc.,
1862
 
        in case the user has not given any value.
1863
 
 
1864
 
        Note that when using the embedded server, the datadirectory is not
1865
 
        necessarily the current directory of this program. */
1866
 
 
1867
 
        /* It's better to use current lib, to keep paths short */
1868
 
        current_dir[0] = FN_CURLIB;
1869
 
        current_dir[1] = FN_LIBCHAR;
1870
 
        current_dir[2] = 0;
1871
 
        default_path = current_dir;
1872
 
 
1873
 
        ut_a(default_path);
1874
 
 
1875
 
        srv_set_thread_priorities = TRUE;
1876
 
        srv_query_thread_priority = QUERY_PRIOR;
1877
 
 
1878
 
        /* Set InnoDB initialization parameters according to the values
1879
 
        read from MySQL .cnf file */
1880
 
 
1881
 
        /*--------------- Data files -------------------------*/
1882
 
 
1883
 
        /* The default dir for data files is the datadir of MySQL */
1884
 
 
1885
 
        srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
1886
 
                         default_path);
1887
 
 
1888
 
        /* Set default InnoDB data file size to 10 MB and let it be
1889
 
        auto-extending. Thus users can use InnoDB in >= 4.0 without having
1890
 
        to specify any startup options. */
1891
 
 
1892
 
        if (!innobase_data_file_path) {
1893
 
                innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
1894
 
        }
1895
 
 
1896
 
        /* Since InnoDB edits the argument in the next call, we make another
1897
 
        copy of it: */
1898
 
 
1899
 
        internal_innobase_data_file_path = strdup(innobase_data_file_path);
1900
 
 
1901
 
        ret = (bool) srv_parse_data_file_paths_and_sizes(
1902
 
                internal_innobase_data_file_path);
1903
 
        if (ret == FALSE) {
1904
 
                errmsg_printf(ERRMSG_LVL_ERROR, 
1905
 
                        "InnoDB: syntax error in innodb_data_file_path");
 
1840
  /* Check that values don't overflow on 32-bit systems. */
 
1841
  if (sizeof(ulint) == 4) {
 
1842
    if (innobase_buffer_pool_size > UINT32_MAX) {
 
1843
      errmsg_printf(ERRMSG_LVL_ERROR, 
 
1844
        "innobase_buffer_pool_size can't be over 4GB"
 
1845
        " on 32-bit systems");
 
1846
 
 
1847
      goto error;
 
1848
    }
 
1849
 
 
1850
    if (innobase_log_file_size > UINT32_MAX) {
 
1851
      errmsg_printf(ERRMSG_LVL_ERROR, 
 
1852
        "innobase_log_file_size can't be over 4GB"
 
1853
        " on 32-bit systems");
 
1854
 
 
1855
      goto error;
 
1856
    }
 
1857
  }
 
1858
 
 
1859
  os_innodb_umask = (ulint)internal::my_umask;
 
1860
 
 
1861
  /* First calculate the default path for innodb_data_home_dir etc.,
 
1862
  in case the user has not given any value.
 
1863
 
 
1864
  Note that when using the embedded server, the datadirectory is not
 
1865
  necessarily the current directory of this program. */
 
1866
 
 
1867
  /* It's better to use current lib, to keep paths short */
 
1868
  current_dir[0] = FN_CURLIB;
 
1869
  current_dir[1] = FN_LIBCHAR;
 
1870
  current_dir[2] = 0;
 
1871
  default_path = current_dir;
 
1872
 
 
1873
  ut_a(default_path);
 
1874
 
 
1875
  srv_set_thread_priorities = TRUE;
 
1876
  srv_query_thread_priority = QUERY_PRIOR;
 
1877
 
 
1878
  /* Set InnoDB initialization parameters according to the values
 
1879
  read from MySQL .cnf file */
 
1880
 
 
1881
  /*--------------- Data files -------------------------*/
 
1882
 
 
1883
  /* The default dir for data files is the datadir of MySQL */
 
1884
 
 
1885
  srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
 
1886
       default_path);
 
1887
 
 
1888
  /* Set default InnoDB data file size to 10 MB and let it be
 
1889
  auto-extending. Thus users can use InnoDB in >= 4.0 without having
 
1890
  to specify any startup options. */
 
1891
 
 
1892
  if (!innobase_data_file_path) {
 
1893
    innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
 
1894
  }
 
1895
 
 
1896
  /* Since InnoDB edits the argument in the next call, we make another
 
1897
  copy of it: */
 
1898
 
 
1899
  internal_innobase_data_file_path = strdup(innobase_data_file_path);
 
1900
 
 
1901
  ret = (bool) srv_parse_data_file_paths_and_sizes(
 
1902
    internal_innobase_data_file_path);
 
1903
  if (ret == FALSE) {
 
1904
    errmsg_printf(ERRMSG_LVL_ERROR, 
 
1905
      "InnoDB: syntax error in innodb_data_file_path");
1906
1906
mem_free_and_error:
1907
 
                srv_free_paths_and_sizes();
1908
 
                if (internal_innobase_data_file_path)
1909
 
                  free(internal_innobase_data_file_path);
1910
 
                goto error;
1911
 
        }
1912
 
 
1913
 
        /* -------------- Log files ---------------------------*/
1914
 
 
1915
 
        /* The default dir for log files is the datadir of MySQL */
1916
 
 
1917
 
        if (!innobase_log_group_home_dir) {
1918
 
                innobase_log_group_home_dir = default_path;
1919
 
        }
 
1907
    srv_free_paths_and_sizes();
 
1908
    if (internal_innobase_data_file_path)
 
1909
      free(internal_innobase_data_file_path);
 
1910
    goto error;
 
1911
  }
 
1912
 
 
1913
  /* -------------- Log files ---------------------------*/
 
1914
 
 
1915
  /* The default dir for log files is the datadir of MySQL */
 
1916
 
 
1917
  if (!innobase_log_group_home_dir) {
 
1918
    innobase_log_group_home_dir = default_path;
 
1919
  }
1920
1920
 
1921
1921
#ifdef UNIV_LOG_ARCHIVE
1922
 
        /* Since innodb_log_arch_dir has no relevance under MySQL,
1923
 
        starting from 4.0.6 we always set it the same as
1924
 
        innodb_log_group_home_dir: */
1925
 
 
1926
 
        innobase_log_arch_dir = innobase_log_group_home_dir;
1927
 
 
1928
 
        srv_arch_dir = innobase_log_arch_dir;
 
1922
  /* Since innodb_log_arch_dir has no relevance under MySQL,
 
1923
  starting from 4.0.6 we always set it the same as
 
1924
  innodb_log_group_home_dir: */
 
1925
 
 
1926
  innobase_log_arch_dir = innobase_log_group_home_dir;
 
1927
 
 
1928
  srv_arch_dir = innobase_log_arch_dir;
1929
1929
#endif /* UNIG_LOG_ARCHIVE */
1930
1930
 
1931
 
        ret = (bool)
1932
 
                srv_parse_log_group_home_dirs(innobase_log_group_home_dir);
1933
 
 
1934
 
        if (ret == FALSE || innobase_mirrored_log_groups != 1) {
1935
 
          errmsg_printf(ERRMSG_LVL_ERROR, "syntax error in innodb_log_group_home_dir, or a "
1936
 
                          "wrong number of mirrored log groups");
1937
 
 
1938
 
                goto mem_free_and_error;
1939
 
        }
1940
 
 
1941
 
        /* Validate the file format by animal name */
1942
 
        if (innobase_file_format_name != NULL) {
1943
 
 
1944
 
                format_id = innobase_file_format_name_lookup(
1945
 
                        innobase_file_format_name);
1946
 
 
1947
 
                if (format_id > DICT_TF_FORMAT_MAX) {
1948
 
 
1949
 
                        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: wrong innodb_file_format.");
1950
 
 
1951
 
                        goto mem_free_and_error;
1952
 
                }
1953
 
        } else {
1954
 
                /* Set it to the default file format id. Though this
1955
 
                should never happen. */
1956
 
                format_id = 0;
1957
 
        }
1958
 
 
1959
 
        srv_file_format = format_id;
1960
 
 
1961
 
        /* Given the type of innobase_file_format_name we have little
1962
 
        choice but to cast away the constness from the returned name.
1963
 
        innobase_file_format_name is used in the MySQL set variable
1964
 
        interface and so can't be const. */
1965
 
 
1966
 
        innobase_file_format_name = 
1967
 
                (char*) trx_sys_file_format_id_to_name(format_id);
1968
 
 
1969
 
        /* Process innobase_file_format_check variable */
1970
 
        ut_a(innobase_file_format_check != NULL);
1971
 
 
1972
 
        /* As a side effect it will set srv_check_file_format_at_startup
1973
 
        on valid input. First we check for "on"/"off". */
1974
 
        if (!innobase_file_format_check_on_off(innobase_file_format_check)) {
1975
 
 
1976
 
                /* Did the user specify a format name that we support ?
1977
 
                As a side effect it will update the variable
1978
 
                srv_check_file_format_at_startup */
1979
 
                if (!innobase_file_format_check_validate(
1980
 
                        innobase_file_format_check)) {
1981
 
 
1982
 
                        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: invalid "
1983
 
                                        "innodb_file_format_check value: "
1984
 
                                        "should be either 'on' or 'off' or "
1985
 
                                        "any value up to %s or its "
1986
 
                                        "equivalent numeric id",
1987
 
                                        trx_sys_file_format_id_to_name(
1988
 
                                                DICT_TF_FORMAT_MAX));
1989
 
 
1990
 
                        goto mem_free_and_error;
1991
 
                }
1992
 
        }
1993
 
 
1994
 
        if (innobase_change_buffering) {
1995
 
                ulint   use;
1996
 
 
1997
 
                for (use = 0;
1998
 
                     use < UT_ARR_SIZE(innobase_change_buffering_values);
1999
 
                     use++) {
2000
 
                        if (!innobase_strcasecmp(
2001
 
                                    innobase_change_buffering,
2002
 
                                    innobase_change_buffering_values[use])) {
2003
 
                                ibuf_use = (ibuf_use_t) use;
2004
 
                                goto innobase_change_buffering_inited_ok;
2005
 
                        }
2006
 
                }
2007
 
 
2008
 
                errmsg_printf(ERRMSG_LVL_ERROR,
2009
 
                                "InnoDB: invalid value "
2010
 
                                "innodb_file_format_check=%s",
2011
 
                                innobase_change_buffering);
2012
 
                goto mem_free_and_error;
2013
 
        }
 
1931
  ret = (bool)
 
1932
    srv_parse_log_group_home_dirs(innobase_log_group_home_dir);
 
1933
 
 
1934
  if (ret == FALSE || innobase_mirrored_log_groups != 1) {
 
1935
    errmsg_printf(ERRMSG_LVL_ERROR, "syntax error in innodb_log_group_home_dir, or a "
 
1936
        "wrong number of mirrored log groups");
 
1937
 
 
1938
    goto mem_free_and_error;
 
1939
  }
 
1940
 
 
1941
  /* Validate the file format by animal name */
 
1942
  if (innobase_file_format_name != NULL) {
 
1943
 
 
1944
    format_id = innobase_file_format_name_lookup(
 
1945
      innobase_file_format_name);
 
1946
 
 
1947
    if (format_id > DICT_TF_FORMAT_MAX) {
 
1948
 
 
1949
      errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: wrong innodb_file_format.");
 
1950
 
 
1951
      goto mem_free_and_error;
 
1952
    }
 
1953
  } else {
 
1954
    /* Set it to the default file format id. Though this
 
1955
    should never happen. */
 
1956
    format_id = 0;
 
1957
  }
 
1958
 
 
1959
  srv_file_format = format_id;
 
1960
 
 
1961
  /* Given the type of innobase_file_format_name we have little
 
1962
  choice but to cast away the constness from the returned name.
 
1963
  innobase_file_format_name is used in the MySQL set variable
 
1964
  interface and so can't be const. */
 
1965
 
 
1966
  innobase_file_format_name = 
 
1967
    (char*) trx_sys_file_format_id_to_name(format_id);
 
1968
 
 
1969
  /* Process innobase_file_format_check variable */
 
1970
  ut_a(innobase_file_format_check != NULL);
 
1971
 
 
1972
  /* As a side effect it will set srv_check_file_format_at_startup
 
1973
  on valid input. First we check for "on"/"off". */
 
1974
  if (!innobase_file_format_check_on_off(innobase_file_format_check)) {
 
1975
 
 
1976
    /* Did the user specify a format name that we support ?
 
1977
    As a side effect it will update the variable
 
1978
    srv_check_file_format_at_startup */
 
1979
    if (!innobase_file_format_check_validate(
 
1980
      innobase_file_format_check)) {
 
1981
 
 
1982
      errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: invalid "
 
1983
          "innodb_file_format_check value: "
 
1984
          "should be either 'on' or 'off' or "
 
1985
          "any value up to %s or its "
 
1986
          "equivalent numeric id",
 
1987
          trx_sys_file_format_id_to_name(
 
1988
            DICT_TF_FORMAT_MAX));
 
1989
 
 
1990
      goto mem_free_and_error;
 
1991
    }
 
1992
  }
 
1993
 
 
1994
  if (innobase_change_buffering) {
 
1995
    ulint use;
 
1996
 
 
1997
    for (use = 0;
 
1998
         use < UT_ARR_SIZE(innobase_change_buffering_values);
 
1999
         use++) {
 
2000
      if (!innobase_strcasecmp(
 
2001
            innobase_change_buffering,
 
2002
            innobase_change_buffering_values[use])) {
 
2003
        ibuf_use = (ibuf_use_t) use;
 
2004
        goto innobase_change_buffering_inited_ok;
 
2005
      }
 
2006
    }
 
2007
 
 
2008
    errmsg_printf(ERRMSG_LVL_ERROR,
 
2009
        "InnoDB: invalid value "
 
2010
        "innodb_file_format_check=%s",
 
2011
        innobase_change_buffering);
 
2012
    goto mem_free_and_error;
 
2013
  }
2014
2014
 
2015
2015
innobase_change_buffering_inited_ok:
2016
 
        ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
2017
 
        innobase_change_buffering = (char*)
2018
 
                innobase_change_buffering_values[ibuf_use];
2019
 
 
2020
 
        /* --------------------------------------------------*/
2021
 
 
2022
 
        srv_file_flush_method_str = innobase_unix_file_flush_method;
2023
 
 
2024
 
        srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
2025
 
        srv_n_log_files = (ulint) innobase_log_files_in_group;
2026
 
        srv_log_file_size = (ulint) innobase_log_file_size;
 
2016
  ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
 
2017
  innobase_change_buffering = (char*)
 
2018
    innobase_change_buffering_values[ibuf_use];
 
2019
 
 
2020
  /* --------------------------------------------------*/
 
2021
 
 
2022
  srv_file_flush_method_str = innobase_unix_file_flush_method;
 
2023
 
 
2024
  srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
 
2025
  srv_n_log_files = (ulint) innobase_log_files_in_group;
 
2026
  srv_log_file_size = (ulint) innobase_log_file_size;
2027
2027
 
2028
2028
#ifdef UNIV_LOG_ARCHIVE
2029
 
        srv_log_archive_on = (ulint) innobase_log_archive;
 
2029
  srv_log_archive_on = (ulint) innobase_log_archive;
2030
2030
#endif /* UNIV_LOG_ARCHIVE */
2031
 
        srv_log_buffer_size = (ulint) innobase_log_buffer_size;
2032
 
 
2033
 
        srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
2034
 
 
2035
 
        srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
2036
 
 
2037
 
        srv_n_file_io_threads = (ulint) innobase_file_io_threads;
2038
 
        srv_n_read_io_threads = (ulint) innobase_read_io_threads;
2039
 
        srv_n_write_io_threads = (ulint) innobase_write_io_threads;
2040
 
 
2041
 
        srv_force_recovery = (ulint) innobase_force_recovery;
2042
 
 
2043
 
        srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
2044
 
        srv_use_checksums = (ibool) innobase_use_checksums;
 
2031
  srv_log_buffer_size = (ulint) innobase_log_buffer_size;
 
2032
 
 
2033
  srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
 
2034
 
 
2035
  srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
 
2036
 
 
2037
  srv_n_file_io_threads = (ulint) innobase_file_io_threads;
 
2038
  srv_n_read_io_threads = (ulint) innobase_read_io_threads;
 
2039
  srv_n_write_io_threads = (ulint) innobase_write_io_threads;
 
2040
 
 
2041
  srv_force_recovery = (ulint) innobase_force_recovery;
 
2042
 
 
2043
  srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
 
2044
  srv_use_checksums = (ibool) innobase_use_checksums;
2045
2045
 
2046
2046
#ifdef HAVE_LARGE_PAGES
2047
2047
        if ((os_use_large_pages = (ibool) my_use_large_pages))
2048
 
                os_large_page_size = (ulint) opt_large_page_size;
 
2048
    os_large_page_size = (ulint) opt_large_page_size;
2049
2049
#endif
2050
2050
 
2051
 
        row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
2052
 
 
2053
 
        srv_locks_unsafe_for_binlog = (ibool) TRUE;
2054
 
 
2055
 
        srv_max_n_open_files = (ulint) innobase_open_files;
2056
 
        srv_innodb_status = (ibool) innobase_create_status_file;
2057
 
 
2058
 
        srv_print_verbose_log = true;
2059
 
 
2060
 
        /* Store the default charset-collation number of this MySQL
2061
 
        installation */
2062
 
 
2063
 
        data_mysql_default_charset_coll = (ulint)default_charset_info->number;
2064
 
 
2065
 
 
2066
 
        innobase_commit_concurrency_init_default();
2067
 
 
2068
 
        /* Since we in this module access directly the fields of a trx
2069
 
        struct, and due to different headers and flags it might happen that
2070
 
        mutex_t has a different size in this module and in InnoDB
2071
 
        modules, we check at run time that the size is the same in
2072
 
        these compilation modules. */
2073
 
 
2074
 
        err = innobase_start_or_create_for_mysql();
2075
 
 
2076
 
        if (err != DB_SUCCESS) {
2077
 
                goto mem_free_and_error;
2078
 
        }
2079
 
 
2080
 
        innobase_open_tables = hash_create(200);
2081
 
        pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
2082
 
        pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
2083
 
        pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
2084
 
        pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
2085
 
        pthread_cond_init(&commit_cond, NULL);
2086
 
        innodb_inited= 1;
 
2051
  row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
 
2052
 
 
2053
  srv_locks_unsafe_for_binlog = (ibool) TRUE;
 
2054
 
 
2055
  srv_max_n_open_files = (ulint) innobase_open_files;
 
2056
  srv_innodb_status = (ibool) innobase_create_status_file;
 
2057
 
 
2058
  srv_print_verbose_log = true;
 
2059
 
 
2060
  /* Store the default charset-collation number of this MySQL
 
2061
  installation */
 
2062
 
 
2063
  data_mysql_default_charset_coll = (ulint)default_charset_info->number;
 
2064
 
 
2065
 
 
2066
  innobase_commit_concurrency_init_default();
 
2067
 
 
2068
  /* Since we in this module access directly the fields of a trx
 
2069
  struct, and due to different headers and flags it might happen that
 
2070
  mutex_t has a different size in this module and in InnoDB
 
2071
  modules, we check at run time that the size is the same in
 
2072
  these compilation modules. */
 
2073
 
 
2074
  err = innobase_start_or_create_for_mysql();
 
2075
 
 
2076
  if (err != DB_SUCCESS) {
 
2077
    goto mem_free_and_error;
 
2078
  }
 
2079
 
 
2080
  innobase_open_tables = hash_create(200);
 
2081
  pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
 
2082
  pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
 
2083
  pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
 
2084
  pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
 
2085
  pthread_cond_init(&commit_cond, NULL);
 
2086
  innodb_inited= 1;
2087
2087
 
2088
2088
        status_table_function_ptr= new InnodbStatusTool;
2089
2089
 
2090
 
        context.add(innodb_engine_ptr);
2091
 
 
2092
 
        context.add(status_table_function_ptr);
2093
 
 
2094
 
        cmp_tool= new(std::nothrow)CmpTool(false);
2095
 
        context.add(cmp_tool);
2096
 
 
2097
 
        cmp_reset_tool= new(std::nothrow)CmpTool(true);
2098
 
        context.add(cmp_reset_tool);
2099
 
 
2100
 
        cmp_mem_tool= new(std::nothrow)CmpmemTool(false);
2101
 
        context.add(cmp_mem_tool);
2102
 
 
2103
 
        cmp_mem_reset_tool= new(std::nothrow)CmpmemTool(true);
2104
 
        context.add(cmp_mem_reset_tool);
2105
 
 
2106
 
        innodb_trx_tool= new(std::nothrow)InnodbTrxTool("INNODB_TRX");
2107
 
        context.add(innodb_trx_tool);
2108
 
 
2109
 
        innodb_locks_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCKS");
2110
 
        context.add(innodb_locks_tool);
2111
 
 
2112
 
        innodb_lock_waits_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCK_WAITS");
2113
 
        context.add(innodb_lock_waits_tool);
2114
 
 
2115
 
        /* Get the current high water mark format. */
2116
 
        innobase_file_format_check = (char*) trx_sys_file_format_max_get();
2117
 
 
2118
 
        return(FALSE);
 
2090
  context.add(innodb_engine_ptr);
 
2091
 
 
2092
  context.add(status_table_function_ptr);
 
2093
 
 
2094
  cmp_tool= new(std::nothrow)CmpTool(false);
 
2095
  context.add(cmp_tool);
 
2096
 
 
2097
  cmp_reset_tool= new(std::nothrow)CmpTool(true);
 
2098
  context.add(cmp_reset_tool);
 
2099
 
 
2100
  cmp_mem_tool= new(std::nothrow)CmpmemTool(false);
 
2101
  context.add(cmp_mem_tool);
 
2102
 
 
2103
  cmp_mem_reset_tool= new(std::nothrow)CmpmemTool(true);
 
2104
  context.add(cmp_mem_reset_tool);
 
2105
 
 
2106
  innodb_trx_tool= new(std::nothrow)InnodbTrxTool("INNODB_TRX");
 
2107
  context.add(innodb_trx_tool);
 
2108
 
 
2109
  innodb_locks_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCKS");
 
2110
  context.add(innodb_locks_tool);
 
2111
 
 
2112
  innodb_lock_waits_tool= new(std::nothrow)InnodbTrxTool("INNODB_LOCK_WAITS");
 
2113
  context.add(innodb_lock_waits_tool);
 
2114
 
 
2115
  /* Get the current high water mark format. */
 
2116
  innobase_file_format_check = (char*) trx_sys_file_format_max_get();
 
2117
 
 
2118
  return(FALSE);
2119
2119
error:
2120
 
        return(TRUE);
 
2120
  return(TRUE);
2121
2121
}
2122
2122
 
2123
2123
 
2124
2124
/****************************************************************//**
2125
2125
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
2126
2126
the logs, and the name of this function should be innobase_checkpoint.
2127
 
@return TRUE if error */
 
2127
@return TRUE if error */
2128
2128
bool
2129
2129
InnobaseEngine::flush_logs()
2130
2130
/*=====================*/
2131
2131
{
2132
 
        bool    result = 0;
2133
 
 
2134
 
        assert(this == innodb_engine_ptr);
2135
 
 
2136
 
        log_buffer_flush_to_disk();
2137
 
 
2138
 
        return(result);
 
2132
  bool  result = 0;
 
2133
 
 
2134
  assert(this == innodb_engine_ptr);
 
2135
 
 
2136
  log_buffer_flush_to_disk();
 
2137
 
 
2138
  return(result);
2139
2139
}
2140
2140
 
2141
2141
/*****************************************************************//**
2144
2144
void
2145
2145
innobase_commit_low(
2146
2146
/*================*/
2147
 
        trx_t*  trx)    /*!< in: transaction handle */
 
2147
  trx_t*  trx)  /*!< in: transaction handle */
2148
2148
{
2149
 
        if (trx->conc_state == TRX_NOT_STARTED) {
2150
 
 
2151
 
                return;
2152
 
        }
2153
 
 
2154
 
        trx_commit_for_mysql(trx);
 
2149
  if (trx->conc_state == TRX_NOT_STARTED) {
 
2150
 
 
2151
    return;
 
2152
  }
 
2153
 
 
2154
  trx_commit_for_mysql(trx);
2155
2155
}
2156
2156
 
2157
2157
/*****************************************************************//**
2159
2159
Starts a new InnoDB transaction if a transaction is not yet started. And
2160
2160
assigns a new snapshot for a consistent read if the transaction does not yet
2161
2161
have one.
2162
 
@return 0 */
 
2162
@return 0 */
2163
2163
int
2164
2164
InnobaseEngine::doStartTransaction(
2165
2165
/*====================================*/
2166
 
        Session*        session,        /*!< in: MySQL thread handle of the user for whom
2167
 
                                                 the transaction should be committed */
 
2166
  Session*  session,  /*!< in: MySQL thread handle of the user for whom
 
2167
                               the transaction should be committed */
2168
2168
  start_transaction_option_t options)
2169
2169
{
2170
 
        assert(this == innodb_engine_ptr);
2171
 
 
2172
 
        /* Create a new trx struct for session, if it does not yet have one */
2173
 
        trx_t *trx = check_trx_exists(session);
2174
 
 
2175
 
        /* This is just to play safe: release a possible FIFO ticket and
2176
 
        search latch. Since we will reserve the kernel mutex, we have to
2177
 
        release the search system latch first to obey the latching order. */
2178
 
        innobase_release_stat_resources(trx);
2179
 
 
2180
 
        /* If the transaction is not started yet, start it */
2181
 
        trx_start_if_not_started(trx);
2182
 
 
2183
 
        /* Assign a read view if the transaction does not have it yet */
 
2170
  assert(this == innodb_engine_ptr);
 
2171
 
 
2172
  /* Create a new trx struct for session, if it does not yet have one */
 
2173
  trx_t *trx = check_trx_exists(session);
 
2174
 
 
2175
  /* This is just to play safe: release a possible FIFO ticket and
 
2176
  search latch. Since we will reserve the kernel mutex, we have to
 
2177
  release the search system latch first to obey the latching order. */
 
2178
  innobase_release_stat_resources(trx);
 
2179
 
 
2180
  /* If the transaction is not started yet, start it */
 
2181
  trx_start_if_not_started(trx);
 
2182
 
 
2183
  /* Assign a read view if the transaction does not have it yet */
2184
2184
  if (options == START_TRANS_OPT_WITH_CONS_SNAPSHOT)
2185
 
          trx_assign_read_view(trx);
 
2185
    trx_assign_read_view(trx);
2186
2186
 
2187
 
        return 0;
 
2187
  return 0;
2188
2188
}
2189
2189
 
2190
2190
/*****************************************************************//**
2191
2191
Commits a transaction in an InnoDB database or marks an SQL statement
2192
2192
ended.
2193
 
@return 0 */
 
2193
@return 0 */
2194
2194
int
2195
2195
InnobaseEngine::doCommit(
2196
2196
/*============*/
2197
 
        Session*        session,        /*!< in: MySQL thread handle of the user for whom
2198
 
                        the transaction should be committed */
2199
 
        bool    all)    /*!< in:        TRUE - commit transaction
2200
 
                                FALSE - the current SQL statement ended */
 
2197
  Session*  session,  /*!< in: MySQL thread handle of the user for whom
 
2198
      the transaction should be committed */
 
2199
  bool  all)  /*!< in:  TRUE - commit transaction
 
2200
        FALSE - the current SQL statement ended */
2201
2201
{
2202
 
        trx_t*          trx;
2203
 
 
2204
 
        assert(this == innodb_engine_ptr);
2205
 
 
2206
 
        trx = check_trx_exists(session);
2207
 
 
2208
 
        /* Since we will reserve the kernel mutex, we have to release
2209
 
        the search system latch first to obey the latching order. */
2210
 
 
2211
 
        if (trx->has_search_latch) {
2212
 
                trx_search_latch_release_if_reserved(trx);
2213
 
        }
2214
 
 
2215
 
        if (all
2216
 
                || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
2217
 
 
2218
 
                /* We were instructed to commit the whole transaction, or
2219
 
                this is an SQL statement end and autocommit is on */
2220
 
 
2221
 
                /* We need current binlog position for ibbackup to work.
2222
 
                Note, the position is current because of
2223
 
                prepare_commit_mutex */
 
2202
  trx_t*    trx;
 
2203
 
 
2204
  assert(this == innodb_engine_ptr);
 
2205
 
 
2206
  trx = check_trx_exists(session);
 
2207
 
 
2208
  /* Since we will reserve the kernel mutex, we have to release
 
2209
  the search system latch first to obey the latching order. */
 
2210
 
 
2211
  if (trx->has_search_latch) {
 
2212
    trx_search_latch_release_if_reserved(trx);
 
2213
  }
 
2214
 
 
2215
  if (all
 
2216
    || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
 
2217
 
 
2218
    /* We were instructed to commit the whole transaction, or
 
2219
    this is an SQL statement end and autocommit is on */
 
2220
 
 
2221
    /* We need current binlog position for ibbackup to work.
 
2222
    Note, the position is current because of
 
2223
    prepare_commit_mutex */
2224
2224
retry:
2225
 
                if (innobase_commit_concurrency > 0) {
2226
 
                        pthread_mutex_lock(&commit_cond_m);
2227
 
                        commit_threads++;
 
2225
    if (innobase_commit_concurrency > 0) {
 
2226
      pthread_mutex_lock(&commit_cond_m);
 
2227
      commit_threads++;
2228
2228
 
2229
 
                        if (commit_threads > innobase_commit_concurrency) {
2230
 
                                commit_threads--;
2231
 
                                pthread_cond_wait(&commit_cond,
2232
 
                                        &commit_cond_m);
2233
 
                                pthread_mutex_unlock(&commit_cond_m);
2234
 
                                goto retry;
2235
 
                        }
2236
 
                        else {
2237
 
                                pthread_mutex_unlock(&commit_cond_m);
2238
 
                        }
2239
 
                }
 
2229
      if (commit_threads > innobase_commit_concurrency) {
 
2230
        commit_threads--;
 
2231
        pthread_cond_wait(&commit_cond,
 
2232
          &commit_cond_m);
 
2233
        pthread_mutex_unlock(&commit_cond_m);
 
2234
        goto retry;
 
2235
      }
 
2236
      else {
 
2237
        pthread_mutex_unlock(&commit_cond_m);
 
2238
      }
 
2239
    }
2240
2240
 
2241
2241
                /* Store transaction point for binlog
2242
 
                Later logic tests that this is set to _something_. We need
2243
 
                that logic to fire, even though we do not have a real name. */
2244
 
                trx->mysql_log_file_name = "UNUSED";
2245
 
                trx->mysql_log_offset = 0;
2246
 
 
2247
 
                /* Don't do write + flush right now. For group commit
2248
 
                to work we want to do the flush after releasing the
2249
 
                prepare_commit_mutex. */
2250
 
                trx->flush_log_later = TRUE;
2251
 
                innobase_commit_low(trx);
2252
 
                trx->flush_log_later = FALSE;
2253
 
 
2254
 
                if (innobase_commit_concurrency > 0) {
2255
 
                        pthread_mutex_lock(&commit_cond_m);
2256
 
                        commit_threads--;
2257
 
                        pthread_cond_signal(&commit_cond);
2258
 
                        pthread_mutex_unlock(&commit_cond_m);
2259
 
                }
2260
 
 
2261
 
                /* Now do a write + flush of logs. */
2262
 
                trx_commit_complete_for_mysql(trx);
2263
 
 
2264
 
        } else {
2265
 
                /* We just mark the SQL statement ended and do not do a
2266
 
                transaction commit */
2267
 
 
2268
 
                /* If we had reserved the auto-inc lock for some
2269
 
                table in this SQL statement we release it now */
2270
 
 
2271
 
                row_unlock_table_autoinc_for_mysql(trx);
2272
 
 
2273
 
                /* Store the current undo_no of the transaction so that we
2274
 
                know where to roll back if we have to roll back the next
2275
 
                SQL statement */
2276
 
 
2277
 
                trx_mark_sql_stat_end(trx);
2278
 
        }
2279
 
 
2280
 
        trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
2281
 
 
2282
 
        if (trx->declared_to_be_inside_innodb) {
2283
 
                /* Release our possible ticket in the FIFO */
2284
 
 
2285
 
                srv_conc_force_exit_innodb(trx);
2286
 
        }
2287
 
 
2288
 
        /* Tell the InnoDB server that there might be work for utility
2289
 
        threads: */
2290
 
        srv_active_wake_master_thread();
2291
 
 
2292
 
        return(0);
 
2242
    Later logic tests that this is set to _something_. We need
 
2243
    that logic to fire, even though we do not have a real name. */
 
2244
    trx->mysql_log_file_name = "UNUSED";
 
2245
    trx->mysql_log_offset = 0;
 
2246
 
 
2247
    /* Don't do write + flush right now. For group commit
 
2248
    to work we want to do the flush after releasing the
 
2249
    prepare_commit_mutex. */
 
2250
    trx->flush_log_later = TRUE;
 
2251
    innobase_commit_low(trx);
 
2252
    trx->flush_log_later = FALSE;
 
2253
 
 
2254
    if (innobase_commit_concurrency > 0) {
 
2255
      pthread_mutex_lock(&commit_cond_m);
 
2256
      commit_threads--;
 
2257
      pthread_cond_signal(&commit_cond);
 
2258
      pthread_mutex_unlock(&commit_cond_m);
 
2259
    }
 
2260
 
 
2261
    /* Now do a write + flush of logs. */
 
2262
    trx_commit_complete_for_mysql(trx);
 
2263
 
 
2264
  } else {
 
2265
    /* We just mark the SQL statement ended and do not do a
 
2266
    transaction commit */
 
2267
 
 
2268
    /* If we had reserved the auto-inc lock for some
 
2269
    table in this SQL statement we release it now */
 
2270
 
 
2271
    row_unlock_table_autoinc_for_mysql(trx);
 
2272
 
 
2273
    /* Store the current undo_no of the transaction so that we
 
2274
    know where to roll back if we have to roll back the next
 
2275
    SQL statement */
 
2276
 
 
2277
    trx_mark_sql_stat_end(trx);
 
2278
  }
 
2279
 
 
2280
  trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
 
2281
 
 
2282
  if (trx->declared_to_be_inside_innodb) {
 
2283
    /* Release our possible ticket in the FIFO */
 
2284
 
 
2285
    srv_conc_force_exit_innodb(trx);
 
2286
  }
 
2287
 
 
2288
  /* Tell the InnoDB server that there might be work for utility
 
2289
  threads: */
 
2290
  srv_active_wake_master_thread();
 
2291
 
 
2292
  return(0);
2293
2293
}
2294
2294
 
2295
2295
/*****************************************************************//**
2296
2296
Rolls back a transaction or the latest SQL statement.
2297
 
@return 0 or error number */
 
2297
@return 0 or error number */
2298
2298
int
2299
2299
InnobaseEngine::doRollback(
2300
2300
/*==============*/
2301
 
        Session*        session,/*!< in: handle to the MySQL thread of the user
2302
 
                        whose transaction should be rolled back */
2303
 
        bool    all)    /*!< in:        TRUE - commit transaction
2304
 
                                FALSE - the current SQL statement ended */
 
2301
  Session*  session,/*!< in: handle to the MySQL thread of the user
 
2302
      whose transaction should be rolled back */
 
2303
  bool  all)  /*!< in:  TRUE - commit transaction
 
2304
        FALSE - the current SQL statement ended */
2305
2305
{
2306
 
        int     error = 0;
2307
 
        trx_t*  trx;
2308
 
 
2309
 
        assert(this == innodb_engine_ptr);
2310
 
 
2311
 
        trx = check_trx_exists(session);
2312
 
 
2313
 
        /* Release a possible FIFO ticket and search latch. Since we will
2314
 
        reserve the kernel mutex, we have to release the search system latch
2315
 
        first to obey the latching order. */
2316
 
 
2317
 
        innobase_release_stat_resources(trx);
2318
 
 
2319
 
        /* If we had reserved the auto-inc lock for some table (if
2320
 
        we come here to roll back the latest SQL statement) we
2321
 
        release it now before a possibly lengthy rollback */
2322
 
 
2323
 
        row_unlock_table_autoinc_for_mysql(trx);
2324
 
 
2325
 
        if (all
2326
 
                || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
2327
 
 
2328
 
                error = trx_rollback_for_mysql(trx);
2329
 
        } else {
2330
 
                error = trx_rollback_last_sql_stat_for_mysql(trx);
2331
 
        }
2332
 
 
2333
 
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2306
  int error = 0;
 
2307
  trx_t*  trx;
 
2308
 
 
2309
  assert(this == innodb_engine_ptr);
 
2310
 
 
2311
  trx = check_trx_exists(session);
 
2312
 
 
2313
  /* Release a possible FIFO ticket and search latch. Since we will
 
2314
  reserve the kernel mutex, we have to release the search system latch
 
2315
  first to obey the latching order. */
 
2316
 
 
2317
  innobase_release_stat_resources(trx);
 
2318
 
 
2319
  /* If we had reserved the auto-inc lock for some table (if
 
2320
  we come here to roll back the latest SQL statement) we
 
2321
  release it now before a possibly lengthy rollback */
 
2322
 
 
2323
  row_unlock_table_autoinc_for_mysql(trx);
 
2324
 
 
2325
  if (all
 
2326
    || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
2327
 
 
2328
    error = trx_rollback_for_mysql(trx);
 
2329
  } else {
 
2330
    error = trx_rollback_last_sql_stat_for_mysql(trx);
 
2331
  }
 
2332
 
 
2333
  return(convert_error_code_to_mysql(error, 0, NULL));
2334
2334
}
2335
2335
 
2336
2336
/*****************************************************************//**
2337
2337
Rolls back a transaction
2338
 
@return 0 or error number */
 
2338
@return 0 or error number */
2339
2339
static
2340
2340
int
2341
2341
innobase_rollback_trx(
2342
2342
/*==================*/
2343
 
        trx_t*  trx)    /*!< in: transaction */
 
2343
  trx_t*  trx)  /*!< in: transaction */
2344
2344
{
2345
 
        int     error = 0;
2346
 
 
2347
 
        /* Release a possible FIFO ticket and search latch. Since we will
2348
 
        reserve the kernel mutex, we have to release the search system latch
2349
 
        first to obey the latching order. */
2350
 
 
2351
 
        innobase_release_stat_resources(trx);
2352
 
 
2353
 
        /* If we had reserved the auto-inc lock for some table (if
2354
 
        we come here to roll back the latest SQL statement) we
2355
 
        release it now before a possibly lengthy rollback */
2356
 
 
2357
 
        row_unlock_table_autoinc_for_mysql(trx);
2358
 
 
2359
 
        error = trx_rollback_for_mysql(trx);
2360
 
 
2361
 
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2345
  int error = 0;
 
2346
 
 
2347
  /* Release a possible FIFO ticket and search latch. Since we will
 
2348
  reserve the kernel mutex, we have to release the search system latch
 
2349
  first to obey the latching order. */
 
2350
 
 
2351
  innobase_release_stat_resources(trx);
 
2352
 
 
2353
  /* If we had reserved the auto-inc lock for some table (if
 
2354
  we come here to roll back the latest SQL statement) we
 
2355
  release it now before a possibly lengthy rollback */
 
2356
 
 
2357
  row_unlock_table_autoinc_for_mysql(trx);
 
2358
 
 
2359
  error = trx_rollback_for_mysql(trx);
 
2360
 
 
2361
  return(convert_error_code_to_mysql(error, 0, NULL));
2362
2362
}
2363
2363
 
2364
2364
/*****************************************************************//**
2368
2368
int
2369
2369
InnobaseEngine::doRollbackToSavepoint(
2370
2370
/*===========================*/
2371
 
        Session*        session,                /*!< in: handle to the MySQL thread of the user
2372
 
                                whose transaction should be rolled back */
2373
 
        drizzled::NamedSavepoint &named_savepoint)      /*!< in: savepoint data */
 
2371
  Session*  session,    /*!< in: handle to the MySQL thread of the user
 
2372
        whose transaction should be rolled back */
 
2373
  drizzled::NamedSavepoint &named_savepoint)  /*!< in: savepoint data */
2374
2374
{
2375
 
        ib_int64_t      mysql_binlog_cache_pos;
2376
 
        int             error = 0;
2377
 
        trx_t*          trx;
2378
 
 
2379
 
        assert(this == innodb_engine_ptr);
2380
 
 
2381
 
        trx = check_trx_exists(session);
2382
 
 
2383
 
        /* Release a possible FIFO ticket and search latch. Since we will
2384
 
        reserve the kernel mutex, we have to release the search system latch
2385
 
        first to obey the latching order. */
2386
 
 
2387
 
        innobase_release_stat_resources(trx);
2388
 
 
2389
 
        error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
 
2375
  ib_int64_t  mysql_binlog_cache_pos;
 
2376
  int   error = 0;
 
2377
  trx_t*    trx;
 
2378
 
 
2379
  assert(this == innodb_engine_ptr);
 
2380
 
 
2381
  trx = check_trx_exists(session);
 
2382
 
 
2383
  /* Release a possible FIFO ticket and search latch. Since we will
 
2384
  reserve the kernel mutex, we have to release the search system latch
 
2385
  first to obey the latching order. */
 
2386
 
 
2387
  innobase_release_stat_resources(trx);
 
2388
 
 
2389
  error= (int)trx_rollback_to_savepoint_for_mysql(trx, named_savepoint.getName().c_str(),
2390
2390
                                                        &mysql_binlog_cache_pos);
2391
 
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2391
  return(convert_error_code_to_mysql(error, 0, NULL));
2392
2392
}
2393
2393
 
2394
2394
/*****************************************************************//**
2398
2398
int
2399
2399
InnobaseEngine::doReleaseSavepoint(
2400
2400
/*=======================*/
2401
 
        Session*        session,                /*!< in: handle to the MySQL thread of the user
2402
 
                                whose transaction should be rolled back */
2403
 
        drizzled::NamedSavepoint &named_savepoint)      /*!< in: savepoint data */
 
2401
  Session*  session,    /*!< in: handle to the MySQL thread of the user
 
2402
        whose transaction should be rolled back */
 
2403
  drizzled::NamedSavepoint &named_savepoint)  /*!< in: savepoint data */
2404
2404
{
2405
 
        int             error = 0;
2406
 
        trx_t*          trx;
2407
 
 
2408
 
        assert(this == innodb_engine_ptr);
2409
 
 
2410
 
        trx = check_trx_exists(session);
2411
 
 
2412
 
        error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
2413
 
 
2414
 
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2405
  int   error = 0;
 
2406
  trx_t*    trx;
 
2407
 
 
2408
  assert(this == innodb_engine_ptr);
 
2409
 
 
2410
  trx = check_trx_exists(session);
 
2411
 
 
2412
  error = (int) trx_release_savepoint_for_mysql(trx, named_savepoint.getName().c_str());
 
2413
 
 
2414
  return(convert_error_code_to_mysql(error, 0, NULL));
2415
2415
}
2416
2416
 
2417
2417
/*****************************************************************//**
2418
2418
Sets a transaction savepoint.
2419
 
@return always 0, that is, always succeeds */
 
2419
@return always 0, that is, always succeeds */
2420
2420
int
2421
2421
InnobaseEngine::doSetSavepoint(
2422
2422
/*===============*/
2423
 
        Session*        session,/*!< in: handle to the MySQL thread */
2424
 
        drizzled::NamedSavepoint &named_savepoint)      /*!< in: savepoint data */
 
2423
  Session*  session,/*!< in: handle to the MySQL thread */
 
2424
  drizzled::NamedSavepoint &named_savepoint)  /*!< in: savepoint data */
2425
2425
{
2426
 
        int     error = 0;
2427
 
        trx_t*  trx;
2428
 
 
2429
 
        assert(this == innodb_engine_ptr);
2430
 
 
2431
 
        /*
2432
 
          In the autocommit mode there is no sense to set a savepoint
2433
 
          (unless we are in sub-statement), so SQL layer ensures that
2434
 
          this method is never called in such situation.
2435
 
        */
2436
 
 
2437
 
        trx = check_trx_exists(session);
2438
 
 
2439
 
        /* Release a possible FIFO ticket and search latch. Since we will
2440
 
        reserve the kernel mutex, we have to release the search system latch
2441
 
        first to obey the latching order. */
2442
 
 
2443
 
        innobase_release_stat_resources(trx);
2444
 
 
2445
 
        /* cannot happen outside of transaction */
2446
 
        assert(trx->conc_state != TRX_NOT_STARTED);
2447
 
 
2448
 
        error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
2449
 
 
2450
 
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2426
  int error = 0;
 
2427
  trx_t*  trx;
 
2428
 
 
2429
  assert(this == innodb_engine_ptr);
 
2430
 
 
2431
  /*
 
2432
    In the autocommit mode there is no sense to set a savepoint
 
2433
    (unless we are in sub-statement), so SQL layer ensures that
 
2434
    this method is never called in such situation.
 
2435
  */
 
2436
 
 
2437
  trx = check_trx_exists(session);
 
2438
 
 
2439
  /* Release a possible FIFO ticket and search latch. Since we will
 
2440
  reserve the kernel mutex, we have to release the search system latch
 
2441
  first to obey the latching order. */
 
2442
 
 
2443
  innobase_release_stat_resources(trx);
 
2444
 
 
2445
  /* cannot happen outside of transaction */
 
2446
  assert(trx->conc_state != TRX_NOT_STARTED);
 
2447
 
 
2448
  error = (int) trx_savepoint_for_mysql(trx, named_savepoint.getName().c_str(), (ib_int64_t)0);
 
2449
 
 
2450
  return(convert_error_code_to_mysql(error, 0, NULL));
2451
2451
}
2452
2452
 
2453
2453
/*****************************************************************//**
2454
2454
Frees a possible InnoDB trx object associated with the current Session.
2455
 
@return 0 or error number */
 
2455
@return 0 or error number */
2456
2456
int
2457
2457
InnobaseEngine::close_connection(
2458
2458
/*======================*/
2459
 
        Session*        session)/*!< in: handle to the MySQL thread of the user
2460
 
                        whose resources should be free'd */
 
2459
  Session*  session)/*!< in: handle to the MySQL thread of the user
 
2460
      whose resources should be free'd */
2461
2461
{
2462
 
        trx_t*  trx;
2463
 
 
2464
 
        assert(this == innodb_engine_ptr);
2465
 
        trx = session_to_trx(session);
2466
 
 
2467
 
        ut_a(trx);
 
2462
  trx_t*  trx;
 
2463
 
 
2464
  assert(this == innodb_engine_ptr);
 
2465
  trx = session_to_trx(session);
 
2466
 
 
2467
  ut_a(trx);
2468
2468
 
2469
2469
  assert(session->killed != Session::NOT_KILLED ||
2470
2470
         trx->conc_state == TRX_NOT_STARTED);
2471
2471
 
2472
2472
  /* Warn if rolling back some things... */
2473
 
        if (session->killed != Session::NOT_KILLED &&
 
2473
  if (session->killed != Session::NOT_KILLED &&
2474
2474
      trx->conc_state != TRX_NOT_STARTED &&
2475
2475
      trx->undo_no.low > 0 &&
2476
2476
      global_system_variables.log_warnings)
2482
2482
      (ulong) trx->undo_no.low);
2483
2483
  }
2484
2484
 
2485
 
        innobase_rollback_trx(trx);
2486
 
 
2487
 
        thr_local_free(trx->mysql_thread_id);
2488
 
        trx_free_for_mysql(trx);
2489
 
 
2490
 
        return(0);
 
2485
  innobase_rollback_trx(trx);
 
2486
 
 
2487
  thr_local_free(trx->mysql_thread_id);
 
2488
  trx_free_for_mysql(trx);
 
2489
 
 
2490
  return(0);
2491
2491
}
2492
2492
 
2493
2493
 
2504
2504
ha_innobase::get_row_type() const
2505
2505
/*=============================*/
2506
2506
{
2507
 
        if (prebuilt && prebuilt->table) {
2508
 
                const ulint     flags = prebuilt->table->flags;
2509
 
 
2510
 
                if (UNIV_UNLIKELY(!flags)) {
2511
 
                        return(ROW_TYPE_REDUNDANT);
2512
 
                }
2513
 
 
2514
 
                ut_ad(flags & DICT_TF_COMPACT);
2515
 
 
2516
 
                switch (flags & DICT_TF_FORMAT_MASK) {
2517
 
                case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
2518
 
                        return(ROW_TYPE_COMPACT);
2519
 
                case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT:
2520
 
                        if (flags & DICT_TF_ZSSIZE_MASK) {
2521
 
                                return(ROW_TYPE_COMPRESSED);
2522
 
                        } else {
2523
 
                                return(ROW_TYPE_DYNAMIC);
2524
 
                        }
 
2507
  if (prebuilt && prebuilt->table) {
 
2508
    const ulint flags = prebuilt->table->flags;
 
2509
 
 
2510
    if (UNIV_UNLIKELY(!flags)) {
 
2511
      return(ROW_TYPE_REDUNDANT);
 
2512
    }
 
2513
 
 
2514
    ut_ad(flags & DICT_TF_COMPACT);
 
2515
 
 
2516
    switch (flags & DICT_TF_FORMAT_MASK) {
 
2517
    case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
 
2518
      return(ROW_TYPE_COMPACT);
 
2519
    case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT:
 
2520
      if (flags & DICT_TF_ZSSIZE_MASK) {
 
2521
        return(ROW_TYPE_COMPRESSED);
 
2522
      } else {
 
2523
        return(ROW_TYPE_DYNAMIC);
 
2524
      }
2525
2525
#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
2526
2526
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
2527
2527
#endif
2528
 
                }
2529
 
        }
2530
 
        ut_ad(0);
2531
 
        return(ROW_TYPE_NOT_USED);
 
2528
    }
 
2529
  }
 
2530
  ut_ad(0);
 
2531
  return(ROW_TYPE_NOT_USED);
2532
2532
}
2533
2533
 
2534
2534
 
2538
2538
const char*
2539
2539
ha_innobase::index_type(
2540
2540
/*====================*/
2541
 
        uint)
2542
 
                                /*!< out: index type */
 
2541
  uint)
 
2542
        /*!< out: index type */
2543
2543
{
2544
 
        return("BTREE");
 
2544
  return("BTREE");
2545
2545
}
2546
2546
 
2547
2547
/****************************************************************//**
2548
2548
Returns the maximum number of keys.
2549
 
@return MAX_KEY */
 
2549
@return MAX_KEY */
2550
2550
UNIV_INTERN
2551
2551
uint
2552
2552
InnobaseEngine::max_supported_keys() const
2553
2553
/*===================================*/
2554
2554
{
2555
 
        return(MAX_KEY);
 
2555
  return(MAX_KEY);
2556
2556
}
2557
2557
 
2558
2558
/****************************************************************//**
2559
2559
Returns the maximum key length.
2560
 
@return maximum supported key length, in bytes */
 
2560
@return maximum supported key length, in bytes */
2561
2561
UNIV_INTERN
2562
2562
uint32_t
2563
2563
InnobaseEngine::max_supported_key_length() const
2564
2564
/*=========================================*/
2565
2565
{
2566
 
        /* An InnoDB page must store >= 2 keys; a secondary key record
2567
 
        must also contain the primary key value: max key length is
2568
 
        therefore set to slightly less than 1 / 4 of page size which
2569
 
        is 16 kB; but currently MySQL does not work with keys whose
2570
 
        size is > MAX_KEY_LENGTH */
2571
 
        return(3500);
 
2566
  /* An InnoDB page must store >= 2 keys; a secondary key record
 
2567
  must also contain the primary key value: max key length is
 
2568
  therefore set to slightly less than 1 / 4 of page size which
 
2569
  is 16 kB; but currently MySQL does not work with keys whose
 
2570
  size is > MAX_KEY_LENGTH */
 
2571
  return(3500);
2572
2572
}
2573
2573
 
2574
2574
/****************************************************************//**
2575
2575
Returns the key map of keys that are usable for scanning.
2576
 
@return key_map_full */
 
2576
@return key_map_full */
2577
2577
UNIV_INTERN
2578
2578
const key_map*
2579
2579
ha_innobase::keys_to_use_for_scanning()
2580
2580
{
2581
 
        return(&key_map_full);
 
2581
  return(&key_map_full);
2582
2582
}
2583
2583
 
2584
2584
 
2585
2585
/****************************************************************//**
2586
2586
Determines if the primary key is clustered index.
2587
 
@return true */
 
2587
@return true */
2588
2588
UNIV_INTERN
2589
2589
bool
2590
2590
ha_innobase::primary_key_is_clustered()
2591
2591
{
2592
 
        return(true);
 
2592
  return(true);
2593
2593
}
2594
2594
 
2595
2595
/*****************************************************************//**
2601
2601
void
2602
2602
normalize_table_name(
2603
2603
/*=================*/
2604
 
        char*           norm_name,      /*!< out: normalized name as a
2605
 
                                        null-terminated string */
2606
 
        const char*     name)           /*!< in: table name string */
 
2604
  char*   norm_name,  /*!< out: normalized name as a
 
2605
          null-terminated string */
 
2606
  const char* name)   /*!< in: table name string */
2607
2607
{
2608
 
        const char*     name_ptr;
2609
 
        const char*     db_ptr;
2610
 
        const char*     ptr;
2611
 
 
2612
 
        /* Scan name from the end */
2613
 
 
2614
 
        ptr = strchr(name, '\0')-1;
2615
 
 
2616
 
        while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2617
 
                ptr--;
2618
 
        }
2619
 
 
2620
 
        name_ptr = ptr + 1;
2621
 
 
2622
 
        assert(ptr > name);
2623
 
 
2624
 
        ptr--;
2625
 
 
2626
 
        while (ptr >= name && *ptr != '\\' && *ptr != '/') {
2627
 
                ptr--;
2628
 
        }
2629
 
 
2630
 
        db_ptr = ptr + 1;
2631
 
 
2632
 
        memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
2633
 
 
2634
 
        norm_name[name_ptr - db_ptr - 1] = '/';
 
2608
  const char* name_ptr;
 
2609
  const char* db_ptr;
 
2610
  const char* ptr;
 
2611
 
 
2612
  /* Scan name from the end */
 
2613
 
 
2614
  ptr = strchr(name, '\0')-1;
 
2615
 
 
2616
  while (ptr >= name && *ptr != '\\' && *ptr != '/') {
 
2617
    ptr--;
 
2618
  }
 
2619
 
 
2620
  name_ptr = ptr + 1;
 
2621
 
 
2622
  assert(ptr > name);
 
2623
 
 
2624
  ptr--;
 
2625
 
 
2626
  while (ptr >= name && *ptr != '\\' && *ptr != '/') {
 
2627
    ptr--;
 
2628
  }
 
2629
 
 
2630
  db_ptr = ptr + 1;
 
2631
 
 
2632
  memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
 
2633
 
 
2634
  norm_name[name_ptr - db_ptr - 1] = '/';
2635
2635
 
2636
2636
#ifdef __WIN__
2637
 
        innobase_casedn_str(norm_name);
 
2637
  innobase_casedn_str(norm_name);
2638
2638
#endif
2639
2639
}
2640
2640
 
2641
2641
/********************************************************************//**
2642
2642
Set the autoinc column max value. This should only be called once from
2643
2643
ha_innobase::open(). Therefore there's no need for a covering lock.
2644
 
@return DB_SUCCESS or error code */
 
2644
@return DB_SUCCESS or error code */
2645
2645
UNIV_INTERN
2646
2646
ulint
2647
2647
ha_innobase::innobase_initialize_autoinc()
2648
2648
/*======================================*/
2649
2649
{
2650
 
        dict_index_t*   index;
2651
 
        uint64_t        auto_inc;
2652
 
        const char*     col_name;
2653
 
        ulint           error;
2654
 
 
2655
 
        col_name = table->found_next_number_field->field_name;
2656
 
        index = innobase_get_index(table->s->next_number_index);
2657
 
 
2658
 
        /* Execute SELECT MAX(col_name) FROM TABLE; */
2659
 
        error = row_search_max_autoinc(index, col_name, &auto_inc);
2660
 
 
2661
 
        switch (error) {
2662
 
        case DB_SUCCESS:
2663
 
 
2664
 
                /* At the this stage we don't know the increment
2665
 
                or the offset, so use default inrement of 1. */
2666
 
                ++auto_inc;
2667
 
                break;
2668
 
 
2669
 
        case DB_RECORD_NOT_FOUND:
2670
 
                ut_print_timestamp(stderr);
2671
 
                fprintf(stderr, "  InnoDB: MySQL and InnoDB data "
2672
 
                        "dictionaries are out of sync.\n"
2673
 
                        "InnoDB: Unable to find the AUTOINC column %s in the "
2674
 
                        "InnoDB table %s.\n"
2675
 
                        "InnoDB: We set the next AUTOINC column value to the "
2676
 
                        "maximum possible value,\n"
2677
 
                        "InnoDB: in effect disabling the AUTOINC next value "
2678
 
                        "generation.\n"
2679
 
                        "InnoDB: You can either set the next AUTOINC value "
2680
 
                        "explicitly using ALTER TABLE\n"
2681
 
                        "InnoDB: or fix the data dictionary by recreating "
2682
 
                        "the table.\n",
2683
 
                        col_name, index->table->name);
2684
 
 
2685
 
                auto_inc = 0xFFFFFFFFFFFFFFFFULL;
2686
 
                break;
2687
 
 
2688
 
        default:
2689
 
                return(error);
2690
 
        }
2691
 
 
2692
 
        dict_table_autoinc_initialize(prebuilt->table, auto_inc);
2693
 
 
2694
 
        return(DB_SUCCESS);
 
2650
  dict_index_t* index;
 
2651
  uint64_t  auto_inc;
 
2652
  const char* col_name;
 
2653
  ulint   error;
 
2654
 
 
2655
  col_name = table->found_next_number_field->field_name;
 
2656
  index = innobase_get_index(table->s->next_number_index);
 
2657
 
 
2658
  /* Execute SELECT MAX(col_name) FROM TABLE; */
 
2659
  error = row_search_max_autoinc(index, col_name, &auto_inc);
 
2660
 
 
2661
  switch (error) {
 
2662
  case DB_SUCCESS:
 
2663
 
 
2664
    /* At the this stage we don't know the increment
 
2665
    or the offset, so use default inrement of 1. */
 
2666
    ++auto_inc;
 
2667
    break;
 
2668
 
 
2669
  case DB_RECORD_NOT_FOUND:
 
2670
    ut_print_timestamp(stderr);
 
2671
    fprintf(stderr, "  InnoDB: MySQL and InnoDB data "
 
2672
      "dictionaries are out of sync.\n"
 
2673
      "InnoDB: Unable to find the AUTOINC column %s in the "
 
2674
      "InnoDB table %s.\n"
 
2675
      "InnoDB: We set the next AUTOINC column value to the "
 
2676
      "maximum possible value,\n"
 
2677
      "InnoDB: in effect disabling the AUTOINC next value "
 
2678
      "generation.\n"
 
2679
      "InnoDB: You can either set the next AUTOINC value "
 
2680
      "explicitly using ALTER TABLE\n"
 
2681
      "InnoDB: or fix the data dictionary by recreating "
 
2682
      "the table.\n",
 
2683
      col_name, index->table->name);
 
2684
 
 
2685
    auto_inc = 0xFFFFFFFFFFFFFFFFULL;
 
2686
    break;
 
2687
 
 
2688
  default:
 
2689
    return(error);
 
2690
  }
 
2691
 
 
2692
  dict_table_autoinc_initialize(prebuilt->table, auto_inc);
 
2693
 
 
2694
  return(DB_SUCCESS);
2695
2695
}
2696
2696
 
2697
2697
/*****************************************************************//**
2698
2698
Creates and opens a handle to a table which already exists in an InnoDB
2699
2699
database.
2700
 
@return 1 if error, 0 if success */
 
2700
@return 1 if error, 0 if success */
2701
2701
UNIV_INTERN
2702
2702
int
2703
2703
ha_innobase::open(
2704
2704
/*==============*/
2705
 
        const char*     name,           /*!< in: table name */
2706
 
        int             mode,           /*!< in: not used */
2707
 
        uint            test_if_locked) /*!< in: not used */
 
2705
  const char* name,   /*!< in: table name */
 
2706
  int   mode,   /*!< in: not used */
 
2707
  uint    test_if_locked) /*!< in: not used */
2708
2708
{
2709
 
        dict_table_t*   ib_table;
2710
 
        char            norm_name[1000];
2711
 
        Session*                session;
2712
 
        ulint           retries = 0;
2713
 
        char*           is_part = NULL;
2714
 
 
2715
 
        UT_NOT_USED(mode);
2716
 
        UT_NOT_USED(test_if_locked);
2717
 
 
2718
 
        session = ha_session();
2719
 
 
2720
 
        /* Under some cases Drizzle seems to call this function while
2721
 
        holding btr_search_latch. This breaks the latching order as
2722
 
        we acquire dict_sys->mutex below and leads to a deadlock. */
2723
 
        if (session != NULL) {
2724
 
                getTransactionalEngine()->releaseTemporaryLatches(session);
2725
 
        }
2726
 
 
2727
 
        normalize_table_name(norm_name, name);
2728
 
 
2729
 
        user_session = NULL;
2730
 
 
2731
 
        if (!(share=get_share(name))) {
2732
 
 
2733
 
                return(1);
2734
 
        }
2735
 
 
2736
 
        /* Create buffers for packing the fields of a record. Why
2737
 
        table->stored_rec_length did not work here? Obviously, because char
2738
 
        fields when packed actually became 1 byte longer, when we also
2739
 
        stored the string length as the first byte. */
2740
 
 
2741
 
        upd_and_key_val_buff_len =
2742
 
                                table->s->stored_rec_length
2743
 
                                + table->s->max_key_length
2744
 
                                + MAX_REF_PARTS * 3;
2745
 
        if (!(unsigned char*) memory::multi_malloc(false,
2746
 
                        &upd_buff, upd_and_key_val_buff_len,
2747
 
                        &key_val_buff, upd_and_key_val_buff_len,
2748
 
                        NULL)) {
2749
 
                free_share(share);
2750
 
 
2751
 
                return(1);
2752
 
        }
2753
 
 
2754
 
        /* We look for pattern #P# to see if the table is partitioned
2755
 
        MySQL table. The retry logic for partitioned tables is a
2756
 
        workaround for http://bugs.mysql.com/bug.php?id=33349. Look
2757
 
        at support issue https://support.mysql.com/view.php?id=21080
2758
 
        for more details. */
2759
 
        is_part = strstr(norm_name, "#P#");
 
2709
  dict_table_t* ib_table;
 
2710
  char    norm_name[1000];
 
2711
  Session*    session;
 
2712
  ulint   retries = 0;
 
2713
  char*   is_part = NULL;
 
2714
 
 
2715
  UT_NOT_USED(mode);
 
2716
  UT_NOT_USED(test_if_locked);
 
2717
 
 
2718
  session = ha_session();
 
2719
 
 
2720
  /* Under some cases Drizzle seems to call this function while
 
2721
  holding btr_search_latch. This breaks the latching order as
 
2722
  we acquire dict_sys->mutex below and leads to a deadlock. */
 
2723
  if (session != NULL) {
 
2724
    getTransactionalEngine()->releaseTemporaryLatches(session);
 
2725
  }
 
2726
 
 
2727
  normalize_table_name(norm_name, name);
 
2728
 
 
2729
  user_session = NULL;
 
2730
 
 
2731
  if (!(share=get_share(name))) {
 
2732
 
 
2733
    return(1);
 
2734
  }
 
2735
 
 
2736
  /* Create buffers for packing the fields of a record. Why
 
2737
  table->stored_rec_length did not work here? Obviously, because char
 
2738
  fields when packed actually became 1 byte longer, when we also
 
2739
  stored the string length as the first byte. */
 
2740
 
 
2741
  upd_and_key_val_buff_len =
 
2742
        table->s->stored_rec_length
 
2743
        + table->s->max_key_length
 
2744
        + MAX_REF_PARTS * 3;
 
2745
  if (!(unsigned char*) memory::multi_malloc(false,
 
2746
      &upd_buff, upd_and_key_val_buff_len,
 
2747
      &key_val_buff, upd_and_key_val_buff_len,
 
2748
      NULL)) {
 
2749
    free_share(share);
 
2750
 
 
2751
    return(1);
 
2752
  }
 
2753
 
 
2754
  /* We look for pattern #P# to see if the table is partitioned
 
2755
  MySQL table. The retry logic for partitioned tables is a
 
2756
  workaround for http://bugs.mysql.com/bug.php?id=33349. Look
 
2757
  at support issue https://support.mysql.com/view.php?id=21080
 
2758
  for more details. */
 
2759
  is_part = strstr(norm_name, "#P#");
2760
2760
retry:
2761
 
        /* Get pointer to a table object in InnoDB dictionary cache */
2762
 
        ib_table = dict_table_get(norm_name, TRUE);
2763
 
        
2764
 
        if (NULL == ib_table) {
2765
 
                if (is_part && retries < 10) {
2766
 
                        ++retries;
2767
 
                        os_thread_sleep(100000);
2768
 
                        goto retry;
2769
 
                }
2770
 
 
2771
 
                if (is_part) {
2772
 
                        errmsg_printf(ERRMSG_LVL_ERROR, "Failed to open table %s after "
2773
 
                                        "%lu attemtps.\n", norm_name,
2774
 
                                        retries);
2775
 
                }
2776
 
 
2777
 
                errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find or open table %s from\n"
2778
 
                                "the internal data dictionary of InnoDB "
2779
 
                                "though the .frm file for the\n"
2780
 
                                "table exists. Maybe you have deleted and "
2781
 
                                "recreated InnoDB data\n"
2782
 
                                "files but have forgotten to delete the "
2783
 
                                "corresponding .frm files\n"
2784
 
                                "of InnoDB tables, or you have moved .frm "
2785
 
                                "files to another database?\n"
2786
 
                                "or, the table contains indexes that this "
2787
 
                                "version of the engine\n"
2788
 
                                "doesn't support.\n"
2789
 
                                "See " REFMAN "innodb-troubleshooting.html\n"
2790
 
                                "how you can resolve the problem.\n",
2791
 
                                norm_name);
2792
 
                free_share(share);
2793
 
                free(upd_buff);
2794
 
                errno = ENOENT;
2795
 
 
2796
 
                return(HA_ERR_NO_SUCH_TABLE);
2797
 
        }
2798
 
 
2799
 
        if (ib_table->ibd_file_missing && !session_tablespace_op(session)) {
2800
 
                errmsg_printf(ERRMSG_LVL_ERROR, "MySQL is trying to open a table handle but "
2801
 
                                "the .ibd file for\ntable %s does not exist.\n"
2802
 
                                "Have you deleted the .ibd file from the "
2803
 
                                "database directory under\nthe MySQL datadir, "
2804
 
                                "or have you used DISCARD TABLESPACE?\n"
2805
 
                                "See " REFMAN "innodb-troubleshooting.html\n"
2806
 
                                "how you can resolve the problem.\n",
2807
 
                                norm_name);
2808
 
                free_share(share);
2809
 
                free(upd_buff);
2810
 
                errno = ENOENT;
2811
 
 
2812
 
                dict_table_decrement_handle_count(ib_table, FALSE);
2813
 
                return(HA_ERR_NO_SUCH_TABLE);
2814
 
        }
2815
 
 
2816
 
        prebuilt = row_create_prebuilt(ib_table);
2817
 
 
2818
 
        prebuilt->mysql_row_len = table->s->stored_rec_length;
2819
 
        prebuilt->default_rec = table->s->default_values;
2820
 
        ut_ad(prebuilt->default_rec);
2821
 
 
2822
 
        /* Looks like MySQL-3.23 sometimes has primary key number != 0 */
2823
 
 
2824
 
        primary_key = table->s->primary_key;
2825
 
        key_used_on_scan = primary_key;
2826
 
 
2827
 
        /* Allocate a buffer for a 'row reference'. A row reference is
2828
 
        a string of bytes of length ref_length which uniquely specifies
2829
 
        a row in our table. Note that MySQL may also compare two row
2830
 
        references for equality by doing a simple memcmp on the strings
2831
 
        of length ref_length! */
2832
 
 
2833
 
        if (!row_table_got_default_clust_index(ib_table)) {
2834
 
                if (primary_key >= MAX_KEY) {
2835
 
                  errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has a primary key in InnoDB data "
2836
 
                                  "dictionary, but not in MySQL!", name);
2837
 
                }
2838
 
 
2839
 
                prebuilt->clust_index_was_generated = FALSE;
2840
 
 
2841
 
                /* MySQL allocates the buffer for ref. key_info->key_length
2842
 
                includes space for all key columns + one byte for each column
2843
 
                that may be NULL. ref_length must be as exact as possible to
2844
 
                save space, because all row reference buffers are allocated
2845
 
                based on ref_length. */
2846
 
 
2847
 
                ref_length = table->key_info[primary_key].key_length;
2848
 
        } else {
2849
 
                if (primary_key != MAX_KEY) {
2850
 
                  errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has no primary key in InnoDB data "
2851
 
                                  "dictionary, but has one in MySQL! If you "
2852
 
                                  "created the table with a MySQL version < "
2853
 
                                  "3.23.54 and did not define a primary key, "
2854
 
                                  "but defined a unique key with all non-NULL "
2855
 
                                  "columns, then MySQL internally treats that "
2856
 
                                  "key as the primary key. You can fix this "
2857
 
                                  "error by dump + DROP + CREATE + reimport "
2858
 
                                  "of the table.", name);
2859
 
                }
2860
 
 
2861
 
                prebuilt->clust_index_was_generated = TRUE;
2862
 
 
2863
 
                ref_length = DATA_ROW_ID_LEN;
2864
 
 
2865
 
                /* If we automatically created the clustered index, then
2866
 
                MySQL does not know about it, and MySQL must NOT be aware
2867
 
                of the index used on scan, to make it avoid checking if we
2868
 
                update the column of the index. That is why we assert below
2869
 
                that key_used_on_scan is the undefined value MAX_KEY.
2870
 
                The column is the row id in the automatical generation case,
2871
 
                and it will never be updated anyway. */
2872
 
 
2873
 
                if (key_used_on_scan != MAX_KEY) {
2874
 
                        errmsg_printf(ERRMSG_LVL_WARN, 
2875
 
                                "Table %s key_used_on_scan is %lu even "
2876
 
                                "though there is no primary key inside "
2877
 
                                "InnoDB.", name, (ulong) key_used_on_scan);
2878
 
                }
2879
 
        }
2880
 
 
2881
 
        /* Index block size in InnoDB: used by MySQL in query optimization */
2882
 
        stats.block_size = 16 * 1024;
2883
 
 
2884
 
        /* Init table lock structure */
2885
 
        thr_lock_data_init(&share->lock,&lock,(void*) 0);
2886
 
 
2887
 
        if (prebuilt->table) {
2888
 
                /* We update the highest file format in the system table
2889
 
                space, if this table has higher file format setting. */
2890
 
 
2891
 
                trx_sys_file_format_max_upgrade(
2892
 
                        (const char**) &innobase_file_format_check,
2893
 
                        dict_table_get_format(prebuilt->table));
2894
 
        }
2895
 
 
2896
 
        info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
2897
 
 
2898
 
        /* Only if the table has an AUTOINC column. */
2899
 
        if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
2900
 
                ulint   error;
2901
 
 
2902
 
                dict_table_autoinc_lock(prebuilt->table);
2903
 
 
2904
 
                /* Since a table can already be "open" in InnoDB's internal
2905
 
                data dictionary, we only init the autoinc counter once, the
2906
 
                first time the table is loaded. We can safely reuse the
2907
 
                autoinc value from a previous Drizzle open. */
2908
 
                if (dict_table_autoinc_read(prebuilt->table) == 0) {
2909
 
 
2910
 
                        error = innobase_initialize_autoinc();
2911
 
                        ut_a(error == DB_SUCCESS);
2912
 
                }
2913
 
 
2914
 
                dict_table_autoinc_unlock(prebuilt->table);
2915
 
        }
2916
 
 
2917
 
        return(0);
 
2761
  /* Get pointer to a table object in InnoDB dictionary cache */
 
2762
  ib_table = dict_table_get(norm_name, TRUE);
 
2763
  
 
2764
  if (NULL == ib_table) {
 
2765
    if (is_part && retries < 10) {
 
2766
      ++retries;
 
2767
      os_thread_sleep(100000);
 
2768
      goto retry;
 
2769
    }
 
2770
 
 
2771
    if (is_part) {
 
2772
      errmsg_printf(ERRMSG_LVL_ERROR, "Failed to open table %s after "
 
2773
          "%lu attemtps.\n", norm_name,
 
2774
          retries);
 
2775
    }
 
2776
 
 
2777
    errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find or open table %s from\n"
 
2778
        "the internal data dictionary of InnoDB "
 
2779
        "though the .frm file for the\n"
 
2780
        "table exists. Maybe you have deleted and "
 
2781
        "recreated InnoDB data\n"
 
2782
        "files but have forgotten to delete the "
 
2783
        "corresponding .frm files\n"
 
2784
        "of InnoDB tables, or you have moved .frm "
 
2785
        "files to another database?\n"
 
2786
        "or, the table contains indexes that this "
 
2787
        "version of the engine\n"
 
2788
        "doesn't support.\n"
 
2789
        "See " REFMAN "innodb-troubleshooting.html\n"
 
2790
        "how you can resolve the problem.\n",
 
2791
        norm_name);
 
2792
    free_share(share);
 
2793
    free(upd_buff);
 
2794
    errno = ENOENT;
 
2795
 
 
2796
    return(HA_ERR_NO_SUCH_TABLE);
 
2797
  }
 
2798
 
 
2799
  if (ib_table->ibd_file_missing && !session_tablespace_op(session)) {
 
2800
    errmsg_printf(ERRMSG_LVL_ERROR, "MySQL is trying to open a table handle but "
 
2801
        "the .ibd file for\ntable %s does not exist.\n"
 
2802
        "Have you deleted the .ibd file from the "
 
2803
        "database directory under\nthe MySQL datadir, "
 
2804
        "or have you used DISCARD TABLESPACE?\n"
 
2805
        "See " REFMAN "innodb-troubleshooting.html\n"
 
2806
        "how you can resolve the problem.\n",
 
2807
        norm_name);
 
2808
    free_share(share);
 
2809
    free(upd_buff);
 
2810
    errno = ENOENT;
 
2811
 
 
2812
    dict_table_decrement_handle_count(ib_table, FALSE);
 
2813
    return(HA_ERR_NO_SUCH_TABLE);
 
2814
  }
 
2815
 
 
2816
  prebuilt = row_create_prebuilt(ib_table);
 
2817
 
 
2818
  prebuilt->mysql_row_len = table->s->stored_rec_length;
 
2819
  prebuilt->default_rec = table->s->default_values;
 
2820
  ut_ad(prebuilt->default_rec);
 
2821
 
 
2822
  /* Looks like MySQL-3.23 sometimes has primary key number != 0 */
 
2823
 
 
2824
  primary_key = table->s->primary_key;
 
2825
  key_used_on_scan = primary_key;
 
2826
 
 
2827
  /* Allocate a buffer for a 'row reference'. A row reference is
 
2828
  a string of bytes of length ref_length which uniquely specifies
 
2829
  a row in our table. Note that MySQL may also compare two row
 
2830
  references for equality by doing a simple memcmp on the strings
 
2831
  of length ref_length! */
 
2832
 
 
2833
  if (!row_table_got_default_clust_index(ib_table)) {
 
2834
    if (primary_key >= MAX_KEY) {
 
2835
      errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has a primary key in InnoDB data "
 
2836
          "dictionary, but not in MySQL!", name);
 
2837
    }
 
2838
 
 
2839
    prebuilt->clust_index_was_generated = FALSE;
 
2840
 
 
2841
    /* MySQL allocates the buffer for ref. key_info->key_length
 
2842
    includes space for all key columns + one byte for each column
 
2843
    that may be NULL. ref_length must be as exact as possible to
 
2844
    save space, because all row reference buffers are allocated
 
2845
    based on ref_length. */
 
2846
 
 
2847
    ref_length = table->key_info[primary_key].key_length;
 
2848
  } else {
 
2849
    if (primary_key != MAX_KEY) {
 
2850
      errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has no primary key in InnoDB data "
 
2851
          "dictionary, but has one in MySQL! If you "
 
2852
          "created the table with a MySQL version < "
 
2853
          "3.23.54 and did not define a primary key, "
 
2854
          "but defined a unique key with all non-NULL "
 
2855
          "columns, then MySQL internally treats that "
 
2856
          "key as the primary key. You can fix this "
 
2857
          "error by dump + DROP + CREATE + reimport "
 
2858
          "of the table.", name);
 
2859
    }
 
2860
 
 
2861
    prebuilt->clust_index_was_generated = TRUE;
 
2862
 
 
2863
    ref_length = DATA_ROW_ID_LEN;
 
2864
 
 
2865
    /* If we automatically created the clustered index, then
 
2866
    MySQL does not know about it, and MySQL must NOT be aware
 
2867
    of the index used on scan, to make it avoid checking if we
 
2868
    update the column of the index. That is why we assert below
 
2869
    that key_used_on_scan is the undefined value MAX_KEY.
 
2870
    The column is the row id in the automatical generation case,
 
2871
    and it will never be updated anyway. */
 
2872
 
 
2873
    if (key_used_on_scan != MAX_KEY) {
 
2874
      errmsg_printf(ERRMSG_LVL_WARN, 
 
2875
        "Table %s key_used_on_scan is %lu even "
 
2876
        "though there is no primary key inside "
 
2877
        "InnoDB.", name, (ulong) key_used_on_scan);
 
2878
    }
 
2879
  }
 
2880
 
 
2881
  /* Index block size in InnoDB: used by MySQL in query optimization */
 
2882
  stats.block_size = 16 * 1024;
 
2883
 
 
2884
  /* Init table lock structure */
 
2885
  thr_lock_data_init(&share->lock,&lock,(void*) 0);
 
2886
 
 
2887
  if (prebuilt->table) {
 
2888
    /* We update the highest file format in the system table
 
2889
    space, if this table has higher file format setting. */
 
2890
 
 
2891
    trx_sys_file_format_max_upgrade(
 
2892
      (const char**) &innobase_file_format_check,
 
2893
      dict_table_get_format(prebuilt->table));
 
2894
  }
 
2895
 
 
2896
  info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
 
2897
 
 
2898
  /* Only if the table has an AUTOINC column. */
 
2899
  if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
 
2900
    ulint error;
 
2901
 
 
2902
    dict_table_autoinc_lock(prebuilt->table);
 
2903
 
 
2904
    /* Since a table can already be "open" in InnoDB's internal
 
2905
    data dictionary, we only init the autoinc counter once, the
 
2906
    first time the table is loaded. We can safely reuse the
 
2907
    autoinc value from a previous Drizzle open. */
 
2908
    if (dict_table_autoinc_read(prebuilt->table) == 0) {
 
2909
 
 
2910
      error = innobase_initialize_autoinc();
 
2911
      ut_a(error == DB_SUCCESS);
 
2912
    }
 
2913
 
 
2914
    dict_table_autoinc_unlock(prebuilt->table);
 
2915
  }
 
2916
 
 
2917
  return(0);
2918
2918
}
2919
2919
 
2920
2920
UNIV_INTERN
2921
2921
uint32_t
2922
2922
InnobaseEngine::max_supported_key_part_length() const
2923
2923
{
2924
 
        return(DICT_MAX_INDEX_COL_LEN - 1);
 
2924
  return(DICT_MAX_INDEX_COL_LEN - 1);
2925
2925
}
2926
2926
 
2927
2927
/******************************************************************//**
2928
2928
Closes a handle to an InnoDB table.
2929
 
@return 0 */
 
2929
@return 0 */
2930
2930
UNIV_INTERN
2931
2931
int
2932
2932
ha_innobase::close(void)
2933
2933
/*====================*/
2934
2934
{
2935
 
        Session*        session;
2936
 
 
2937
 
        session = ha_session();
2938
 
        if (session != NULL) {
2939
 
                getTransactionalEngine()->releaseTemporaryLatches(session);
2940
 
        }
2941
 
 
2942
 
        row_prebuilt_free(prebuilt, FALSE);
2943
 
 
2944
 
        free(upd_buff);
2945
 
        free_share(share);
2946
 
 
2947
 
        /* Tell InnoDB server that there might be work for
2948
 
        utility threads: */
2949
 
 
2950
 
        srv_active_wake_master_thread();
2951
 
 
2952
 
        return(0);
 
2935
  Session*  session;
 
2936
 
 
2937
  session = ha_session();
 
2938
  if (session != NULL) {
 
2939
    getTransactionalEngine()->releaseTemporaryLatches(session);
 
2940
  }
 
2941
 
 
2942
  row_prebuilt_free(prebuilt, FALSE);
 
2943
 
 
2944
  free(upd_buff);
 
2945
  free_share(share);
 
2946
 
 
2947
  /* Tell InnoDB server that there might be work for
 
2948
  utility threads: */
 
2949
 
 
2950
  srv_active_wake_master_thread();
 
2951
 
 
2952
  return(0);
2953
2953
}
2954
2954
 
2955
2955
/* The following accessor functions should really be inside MySQL code! */
2956
2956
 
2957
2957
/**************************************************************//**
2958
2958
Gets field offset for a field in a table.
2959
 
@return offset */
 
2959
@return offset */
2960
2960
static inline
2961
2961
uint
2962
2962
get_field_offset(
2963
2963
/*=============*/
2964
 
        Table*  table,  /*!< in: MySQL table object */
2965
 
        Field*  field)  /*!< in: MySQL field object */
 
2964
  Table*  table,  /*!< in: MySQL table object */
 
2965
  Field*  field)  /*!< in: MySQL field object */
2966
2966
{
2967
 
        return((uint) (field->ptr - table->record[0]));
 
2967
  return((uint) (field->ptr - table->record[0]));
2968
2968
}
2969
2969
 
2970
2970
/**************************************************************//**
2971
2971
Checks if a field in a record is SQL NULL. Uses the record format
2972
2972
information in table to track the null bit in record.
2973
 
@return 1 if NULL, 0 otherwise */
 
2973
@return 1 if NULL, 0 otherwise */
2974
2974
static inline
2975
2975
uint
2976
2976
field_in_record_is_null(
2977
2977
/*====================*/
2978
 
        Table*  table,  /*!< in: MySQL table object */
2979
 
        Field*  field,  /*!< in: MySQL field object */
2980
 
        char*   record) /*!< in: a row in MySQL format */
 
2978
  Table*  table,  /*!< in: MySQL table object */
 
2979
  Field*  field,  /*!< in: MySQL field object */
 
2980
  char* record) /*!< in: a row in MySQL format */
2981
2981
{
2982
 
        int     null_offset;
2983
 
 
2984
 
        if (!field->null_ptr) {
2985
 
 
2986
 
                return(0);
2987
 
        }
2988
 
 
2989
 
        null_offset = (uint) ((char*) field->null_ptr
2990
 
                                        - (char*) table->record[0]);
2991
 
 
2992
 
        if (record[null_offset] & field->null_bit) {
2993
 
 
2994
 
                return(1);
2995
 
        }
2996
 
 
2997
 
        return(0);
 
2982
  int null_offset;
 
2983
 
 
2984
  if (!field->null_ptr) {
 
2985
 
 
2986
    return(0);
 
2987
  }
 
2988
 
 
2989
  null_offset = (uint) ((char*) field->null_ptr
 
2990
          - (char*) table->record[0]);
 
2991
 
 
2992
  if (record[null_offset] & field->null_bit) {
 
2993
 
 
2994
    return(1);
 
2995
  }
 
2996
 
 
2997
  return(0);
2998
2998
}
2999
2999
 
3000
3000
/**************************************************************//**
3004
3004
void
3005
3005
set_field_in_record_to_null(
3006
3006
/*========================*/
3007
 
        Table*  table,  /*!< in: MySQL table object */
3008
 
        Field*  field,  /*!< in: MySQL field object */
3009
 
        char*   record) /*!< in: a row in MySQL format */
 
3007
  Table*  table,  /*!< in: MySQL table object */
 
3008
  Field*  field,  /*!< in: MySQL field object */
 
3009
  char* record) /*!< in: a row in MySQL format */
3010
3010
{
3011
 
        int     null_offset;
3012
 
 
3013
 
        null_offset = (uint) ((char*) field->null_ptr
3014
 
                                        - (char*) table->record[0]);
3015
 
 
3016
 
        record[null_offset] = record[null_offset] | field->null_bit;
 
3011
  int null_offset;
 
3012
 
 
3013
  null_offset = (uint) ((char*) field->null_ptr
 
3014
          - (char*) table->record[0]);
 
3015
 
 
3016
  record[null_offset] = record[null_offset] | field->null_bit;
3017
3017
}
3018
3018
 
3019
3019
/*************************************************************//**
3021
3021
is such that we must use MySQL code to compare them. NOTE that the prototype
3022
3022
of this function is in rem0cmp.c in InnoDB source code! If you change this
3023
3023
function, remember to update the prototype there!
3024
 
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
 
3024
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
3025
3025
extern "C" UNIV_INTERN
3026
3026
int
3027
3027
innobase_mysql_cmp(
3028
3028
/*===============*/
3029
 
        int             mysql_type,     /*!< in: MySQL type */
3030
 
        uint            charset_number, /*!< in: number of the charset */
3031
 
        const unsigned char* a,         /*!< in: data field */
3032
 
        unsigned int    a_length,       /*!< in: data field length,
3033
 
                                        not UNIV_SQL_NULL */
3034
 
        const unsigned char* b,         /* in: data field */
3035
 
        unsigned int    b_length);      /* in: data field length,
3036
 
                                        not UNIV_SQL_NULL */
 
3029
  int   mysql_type, /*!< in: MySQL type */
 
3030
  uint    charset_number, /*!< in: number of the charset */
 
3031
  const unsigned char* a,   /*!< in: data field */
 
3032
  unsigned int  a_length, /*!< in: data field length,
 
3033
          not UNIV_SQL_NULL */
 
3034
  const unsigned char* b,   /* in: data field */
 
3035
  unsigned int  b_length);  /* in: data field length,
 
3036
          not UNIV_SQL_NULL */
3037
3037
 
3038
3038
int
3039
3039
innobase_mysql_cmp(
3040
3040
/*===============*/
3041
 
                                        /* out: 1, 0, -1, if a is greater,
3042
 
                                        equal, less than b, respectively */
3043
 
        int             mysql_type,     /* in: MySQL type */
3044
 
        uint            charset_number, /* in: number of the charset */
3045
 
        const unsigned char* a,         /* in: data field */
3046
 
        unsigned int    a_length,       /* in: data field length,
3047
 
                                        not UNIV_SQL_NULL */
3048
 
        const unsigned char* b,         /* in: data field */
3049
 
        unsigned int    b_length)       /* in: data field length,
3050
 
                                        not UNIV_SQL_NULL */
 
3041
          /* out: 1, 0, -1, if a is greater,
 
3042
          equal, less than b, respectively */
 
3043
  int   mysql_type, /* in: MySQL type */
 
3044
  uint    charset_number, /* in: number of the charset */
 
3045
  const unsigned char* a,   /* in: data field */
 
3046
  unsigned int  a_length, /* in: data field length,
 
3047
          not UNIV_SQL_NULL */
 
3048
  const unsigned char* b,   /* in: data field */
 
3049
  unsigned int  b_length) /* in: data field length,
 
3050
          not UNIV_SQL_NULL */
3051
3051
{
3052
 
        const CHARSET_INFO*     charset;
3053
 
        enum_field_types        mysql_tp;
3054
 
        int                     ret;
3055
 
 
3056
 
        assert(a_length != UNIV_SQL_NULL);
3057
 
        assert(b_length != UNIV_SQL_NULL);
3058
 
 
3059
 
        mysql_tp = (enum_field_types) mysql_type;
3060
 
 
3061
 
        switch (mysql_tp) {
3062
 
 
3063
 
        case DRIZZLE_TYPE_BLOB:
3064
 
        case DRIZZLE_TYPE_VARCHAR:
3065
 
                /* Use the charset number to pick the right charset struct for
3066
 
                the comparison. Since the MySQL function get_charset may be
3067
 
                slow before Bar removes the mutex operation there, we first
3068
 
                look at 2 common charsets directly. */
3069
 
 
3070
 
                if (charset_number == default_charset_info->number) {
3071
 
                        charset = default_charset_info;
3072
 
                } else {
3073
 
                        charset = get_charset(charset_number);
3074
 
 
3075
 
                        if (charset == NULL) {
3076
 
                          errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB needs charset %lu for doing "
3077
 
                                          "a comparison, but MySQL cannot "
3078
 
                                          "find that charset.",
3079
 
                                          (ulong) charset_number);
3080
 
                                ut_a(0);
3081
 
                        }
3082
 
                }
3083
 
 
3084
 
                /* Starting from 4.1.3, we use strnncollsp() in comparisons of
3085
 
                non-latin1_swedish_ci strings. NOTE that the collation order
3086
 
                changes then: 'b\0\0...' is ordered BEFORE 'b  ...'. Users
3087
 
                having indexes on such data need to rebuild their tables! */
3088
 
 
3089
 
                ret = charset->coll->strnncollsp(charset,
3090
 
                                  a, a_length,
3091
 
                                                 b, b_length, 0);
3092
 
                if (ret < 0) {
3093
 
                        return(-1);
3094
 
                } else if (ret > 0) {
3095
 
                        return(1);
3096
 
                } else {
3097
 
                        return(0);
3098
 
                }
3099
 
        default:
3100
 
                ut_error;
3101
 
        }
3102
 
 
3103
 
        return(0);
 
3052
  const CHARSET_INFO* charset;
 
3053
  enum_field_types  mysql_tp;
 
3054
  int     ret;
 
3055
 
 
3056
  assert(a_length != UNIV_SQL_NULL);
 
3057
  assert(b_length != UNIV_SQL_NULL);
 
3058
 
 
3059
  mysql_tp = (enum_field_types) mysql_type;
 
3060
 
 
3061
  switch (mysql_tp) {
 
3062
 
 
3063
  case DRIZZLE_TYPE_BLOB:
 
3064
  case DRIZZLE_TYPE_VARCHAR:
 
3065
    /* Use the charset number to pick the right charset struct for
 
3066
    the comparison. Since the MySQL function get_charset may be
 
3067
    slow before Bar removes the mutex operation there, we first
 
3068
    look at 2 common charsets directly. */
 
3069
 
 
3070
    if (charset_number == default_charset_info->number) {
 
3071
      charset = default_charset_info;
 
3072
    } else {
 
3073
      charset = get_charset(charset_number);
 
3074
 
 
3075
      if (charset == NULL) {
 
3076
        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB needs charset %lu for doing "
 
3077
            "a comparison, but MySQL cannot "
 
3078
            "find that charset.",
 
3079
            (ulong) charset_number);
 
3080
        ut_a(0);
 
3081
      }
 
3082
    }
 
3083
 
 
3084
    /* Starting from 4.1.3, we use strnncollsp() in comparisons of
 
3085
    non-latin1_swedish_ci strings. NOTE that the collation order
 
3086
    changes then: 'b\0\0...' is ordered BEFORE 'b  ...'. Users
 
3087
    having indexes on such data need to rebuild their tables! */
 
3088
 
 
3089
    ret = charset->coll->strnncollsp(charset,
 
3090
          a, a_length,
 
3091
             b, b_length, 0);
 
3092
    if (ret < 0) {
 
3093
      return(-1);
 
3094
    } else if (ret > 0) {
 
3095
      return(1);
 
3096
    } else {
 
3097
      return(0);
 
3098
    }
 
3099
  default:
 
3100
    ut_error;
 
3101
  }
 
3102
 
 
3103
  return(0);
3104
3104
}
3105
3105
 
3106
3106
/**************************************************************//**
3107
3107
Converts a MySQL type to an InnoDB type. Note that this function returns
3108
3108
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
3109
3109
VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
3110
 
@return DATA_BINARY, DATA_VARCHAR, ... */
 
3110
@return DATA_BINARY, DATA_VARCHAR, ... */
3111
3111
extern "C" UNIV_INTERN
3112
3112
ulint
3113
3113
get_innobase_type_from_mysql_type(
3114
3114
/*==============================*/
3115
 
        ulint*          unsigned_flag,  /*!< out: DATA_UNSIGNED if an
3116
 
                                        'unsigned type';
3117
 
                                        at least ENUM and SET,
3118
 
                                        and unsigned integer
3119
 
                                        types are 'unsigned types' */
3120
 
        const void*     f)              /*!< in: MySQL Field */
 
3115
  ulint*    unsigned_flag,  /*!< out: DATA_UNSIGNED if an
 
3116
          'unsigned type';
 
3117
          at least ENUM and SET,
 
3118
          and unsigned integer
 
3119
          types are 'unsigned types' */
 
3120
  const void* f)    /*!< in: MySQL Field */
3121
3121
{
3122
 
        const class Field* field = reinterpret_cast<const class Field*>(f);
3123
 
 
3124
 
        /* The following asserts try to check that the MySQL type code fits in
3125
 
        8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
3126
 
        the type */
3127
 
 
3128
 
        assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
3129
 
 
3130
 
        if (field->flags & UNSIGNED_FLAG) {
3131
 
 
3132
 
                *unsigned_flag = DATA_UNSIGNED;
3133
 
        } else {
3134
 
                *unsigned_flag = 0;
3135
 
        }
3136
 
 
3137
 
        if (field->real_type() == DRIZZLE_TYPE_ENUM)
3138
 
        {
3139
 
                /* MySQL has field->type() a string type for these, but the
3140
 
                data is actually internally stored as an unsigned integer
3141
 
                code! */
3142
 
 
3143
 
                *unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
3144
 
                                                flag set to zero, even though
3145
 
                                                internally this is an unsigned
3146
 
                                                integer type */
3147
 
                return(DATA_INT);
3148
 
        }
3149
 
 
3150
 
        switch (field->type()) {
3151
 
                /* NOTE that we only allow string types in DATA_DRIZZLE and
3152
 
                DATA_VARDRIZZLE */
3153
 
        case DRIZZLE_TYPE_VARCHAR:    /* new >= 5.0.3 true VARCHAR */
3154
 
                if (field->binary()) {
3155
 
                        return(DATA_BINARY);
3156
 
                } else {
3157
 
                        return(DATA_VARMYSQL);
3158
 
                }
3159
 
        case DRIZZLE_TYPE_DECIMAL:
3160
 
                return(DATA_FIXBINARY);
3161
 
        case DRIZZLE_TYPE_LONG:
3162
 
        case DRIZZLE_TYPE_LONGLONG:
3163
 
        case DRIZZLE_TYPE_DATETIME:
3164
 
        case DRIZZLE_TYPE_DATE:
3165
 
        case DRIZZLE_TYPE_TIMESTAMP:
3166
 
                return(DATA_INT);
3167
 
        case DRIZZLE_TYPE_DOUBLE:
3168
 
                return(DATA_DOUBLE);
3169
 
        case DRIZZLE_TYPE_BLOB:
 
3122
  const class Field* field = reinterpret_cast<const class Field*>(f);
 
3123
 
 
3124
  /* The following asserts try to check that the MySQL type code fits in
 
3125
  8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
 
3126
  the type */
 
3127
 
 
3128
  assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
 
3129
 
 
3130
  if (field->flags & UNSIGNED_FLAG) {
 
3131
 
 
3132
    *unsigned_flag = DATA_UNSIGNED;
 
3133
  } else {
 
3134
    *unsigned_flag = 0;
 
3135
  }
 
3136
 
 
3137
  if (field->real_type() == DRIZZLE_TYPE_ENUM)
 
3138
  {
 
3139
    /* MySQL has field->type() a string type for these, but the
 
3140
    data is actually internally stored as an unsigned integer
 
3141
    code! */
 
3142
 
 
3143
    *unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
 
3144
            flag set to zero, even though
 
3145
            internally this is an unsigned
 
3146
            integer type */
 
3147
    return(DATA_INT);
 
3148
  }
 
3149
 
 
3150
  switch (field->type()) {
 
3151
    /* NOTE that we only allow string types in DATA_DRIZZLE and
 
3152
    DATA_VARDRIZZLE */
 
3153
  case DRIZZLE_TYPE_VARCHAR:    /* new >= 5.0.3 true VARCHAR */
 
3154
    if (field->binary()) {
 
3155
      return(DATA_BINARY);
 
3156
    } else {
 
3157
      return(DATA_VARMYSQL);
 
3158
    }
 
3159
  case DRIZZLE_TYPE_DECIMAL:
 
3160
    return(DATA_FIXBINARY);
 
3161
  case DRIZZLE_TYPE_LONG:
 
3162
  case DRIZZLE_TYPE_LONGLONG:
 
3163
  case DRIZZLE_TYPE_DATETIME:
 
3164
  case DRIZZLE_TYPE_DATE:
 
3165
  case DRIZZLE_TYPE_TIMESTAMP:
 
3166
    return(DATA_INT);
 
3167
  case DRIZZLE_TYPE_DOUBLE:
 
3168
    return(DATA_DOUBLE);
 
3169
  case DRIZZLE_TYPE_BLOB:
3170
3170
                return(DATA_BLOB);
3171
 
        default:
3172
 
                ut_error;
3173
 
        }
 
3171
  default:
 
3172
    ut_error;
 
3173
  }
3174
3174
 
3175
 
        return(0);
 
3175
  return(0);
3176
3176
}
3177
3177
 
3178
3178
/*******************************************************************//**
3182
3182
void
3183
3183
innobase_write_to_2_little_endian(
3184
3184
/*==============================*/
3185
 
        byte*   buf,    /*!< in: where to store */
3186
 
        ulint   val)    /*!< in: value to write, must be < 64k */
 
3185
  byte* buf,  /*!< in: where to store */
 
3186
  ulint val)  /*!< in: value to write, must be < 64k */
3187
3187
{
3188
 
        ut_a(val < 256 * 256);
 
3188
  ut_a(val < 256 * 256);
3189
3189
 
3190
 
        buf[0] = (byte)(val & 0xFF);
3191
 
        buf[1] = (byte)(val / 256);
 
3190
  buf[0] = (byte)(val & 0xFF);
 
3191
  buf[1] = (byte)(val / 256);
3192
3192
}
3193
3193
 
3194
3194
/*******************************************************************//**
3195
3195
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
3196
3196
storage format.
3197
 
@return value */
 
3197
@return value */
3198
3198
static inline
3199
3199
uint
3200
3200
innobase_read_from_2_little_endian(
3201
3201
/*===============================*/
3202
 
        const unsigned char*    buf)    /*!< in: from where to read */
 
3202
  const unsigned char*  buf)  /*!< in: from where to read */
3203
3203
{
3204
 
        return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
 
3204
  return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
3205
3205
}
3206
3206
 
3207
3207
/*******************************************************************//**
3208
3208
Stores a key value for a row to a buffer.
3209
 
@return key value length as stored in buff */
 
3209
@return key value length as stored in buff */
3210
3210
UNIV_INTERN
3211
3211
uint
3212
3212
ha_innobase::store_key_val_for_row(
3213
3213
/*===============================*/
3214
 
        uint            keynr,  /*!< in: key number */
3215
 
        char*           buff,   /*!< in/out: buffer for the key value (in MySQL
3216
 
                                format) */
3217
 
        uint            buff_len,/*!< in: buffer length */
3218
 
        const unsigned char*    record)/*!< in: row in MySQL format */
 
3214
  uint    keynr,  /*!< in: key number */
 
3215
  char*   buff, /*!< in/out: buffer for the key value (in MySQL
 
3216
        format) */
 
3217
  uint    buff_len,/*!< in: buffer length */
 
3218
  const unsigned char*  record)/*!< in: row in MySQL format */
3219
3219
{
3220
 
        KEY*            key_info        = table->key_info + keynr;
3221
 
        KEY_PART_INFO*  key_part        = key_info->key_part;
3222
 
        KEY_PART_INFO*  end             = key_part + key_info->key_parts;
3223
 
        char*           buff_start      = buff;
3224
 
        enum_field_types mysql_type;
3225
 
        Field*          field;
3226
 
        ibool           is_null;
3227
 
 
3228
 
        /* The format for storing a key field in MySQL is the following:
3229
 
 
3230
 
        1. If the column can be NULL, then in the first byte we put 1 if the
3231
 
        field value is NULL, 0 otherwise.
3232
 
 
3233
 
        2. If the column is of a BLOB type (it must be a column prefix field
3234
 
        in this case), then we put the length of the data in the field to the
3235
 
        next 2 bytes, in the little-endian format. If the field is SQL NULL,
3236
 
        then these 2 bytes are set to 0. Note that the length of data in the
3237
 
        field is <= column prefix length.
3238
 
 
3239
 
        3. In a column prefix field, prefix_len next bytes are reserved for
3240
 
        data. In a normal field the max field length next bytes are reserved
3241
 
        for data. For a VARCHAR(n) the max field length is n. If the stored
3242
 
        value is the SQL NULL then these data bytes are set to 0.
3243
 
 
3244
 
        4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
3245
 
        in the MySQL row format, the length is stored in 1 or 2 bytes,
3246
 
        depending on the maximum allowed length. But in the MySQL key value
3247
 
        format, the length always takes 2 bytes.
3248
 
 
3249
 
        We have to zero-fill the buffer so that MySQL is able to use a
3250
 
        simple memcmp to compare two key values to determine if they are
3251
 
        equal. MySQL does this to compare contents of two 'ref' values. */
3252
 
 
3253
 
        bzero(buff, buff_len);
3254
 
 
3255
 
        for (; key_part != end; key_part++) {
3256
 
                is_null = FALSE;
3257
 
 
3258
 
                if (key_part->null_bit) {
3259
 
                        if (record[key_part->null_offset]
3260
 
                                                & key_part->null_bit) {
3261
 
                                *buff = 1;
3262
 
                                is_null = TRUE;
3263
 
                        } else {
3264
 
                                *buff = 0;
3265
 
                        }
3266
 
                        buff++;
3267
 
                }
3268
 
 
3269
 
                field = key_part->field;
3270
 
                mysql_type = field->type();
3271
 
 
3272
 
                if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
3273
 
                                                /* >= 5.0.3 true VARCHAR */
3274
 
                        ulint           lenlen;
3275
 
                        ulint           len;
3276
 
                        const byte*     data;
3277
 
                        ulint           key_len;
3278
 
                        ulint           true_len;
3279
 
                        const CHARSET_INFO*     cs;
3280
 
                        int             error=0;
3281
 
 
3282
 
                        key_len = key_part->length;
3283
 
 
3284
 
                        if (is_null) {
3285
 
                                buff += key_len + 2;
3286
 
 
3287
 
                                continue;
3288
 
                        }
3289
 
                        cs = field->charset();
3290
 
 
3291
 
                        lenlen = (ulint)
3292
 
                                (((Field_varstring*)field)->length_bytes);
3293
 
 
3294
 
                        data = row_mysql_read_true_varchar(&len,
3295
 
                                (byte*) (record
3296
 
                                + (ulint)get_field_offset(table, field)),
3297
 
                                lenlen);
3298
 
 
3299
 
                        true_len = len;
3300
 
 
3301
 
                        /* For multi byte character sets we need to calculate
3302
 
                        the true length of the key */
3303
 
 
3304
 
                        if (len > 0 && cs->mbmaxlen > 1) {
3305
 
                                true_len = (ulint) cs->cset->well_formed_len(cs,
3306
 
                                                (const char *) data,
3307
 
                                                (const char *) data + len,
3308
 
                                                (uint) (key_len /
3309
 
                                                        cs->mbmaxlen),
3310
 
                                                &error);
3311
 
                        }
3312
 
 
3313
 
                        /* In a column prefix index, we may need to truncate
3314
 
                        the stored value: */
3315
 
 
3316
 
                        if (true_len > key_len) {
3317
 
                                true_len = key_len;
3318
 
                        }
3319
 
 
3320
 
                        /* The length in a key value is always stored in 2
3321
 
                        bytes */
3322
 
 
3323
 
                        row_mysql_store_true_var_len((byte*)buff, true_len, 2);
3324
 
                        buff += 2;
3325
 
 
3326
 
                        memcpy(buff, data, true_len);
3327
 
 
3328
 
                        /* Note that we always reserve the maximum possible
3329
 
                        length of the true VARCHAR in the key value, though
3330
 
                        only len first bytes after the 2 length bytes contain
3331
 
                        actual data. The rest of the space was reset to zero
3332
 
                        in the bzero() call above. */
3333
 
 
3334
 
                        buff += key_len;
3335
 
 
3336
 
                } else if (mysql_type == DRIZZLE_TYPE_BLOB) {
3337
 
 
3338
 
                        const CHARSET_INFO*     cs;
3339
 
                        ulint           key_len;
3340
 
                        ulint           true_len;
3341
 
                        int             error=0;
3342
 
                        ulint           blob_len;
3343
 
                        const byte*     blob_data;
3344
 
 
3345
 
                        ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
3346
 
 
3347
 
                        key_len = key_part->length;
3348
 
 
3349
 
                        if (is_null) {
3350
 
                                buff += key_len + 2;
3351
 
 
3352
 
                                continue;
3353
 
                        }
3354
 
 
3355
 
                        cs = field->charset();
3356
 
 
3357
 
                        blob_data = row_mysql_read_blob_ref(&blob_len,
3358
 
                                (byte*) (record
3359
 
                                + (ulint)get_field_offset(table, field)),
3360
 
                                        (ulint) field->pack_length());
3361
 
 
3362
 
                        true_len = blob_len;
3363
 
 
3364
 
                        ut_a(get_field_offset(table, field)
3365
 
                                == key_part->offset);
3366
 
 
3367
 
                        /* For multi byte character sets we need to calculate
3368
 
                        the true length of the key */
3369
 
 
3370
 
                        if (blob_len > 0 && cs->mbmaxlen > 1) {
3371
 
                                true_len = (ulint) cs->cset->well_formed_len(cs,
3372
 
                                                (const char *) blob_data,
3373
 
                                                (const char *) blob_data
3374
 
                                                        + blob_len,
3375
 
                                                (uint) (key_len /
3376
 
                                                        cs->mbmaxlen),
3377
 
                                                &error);
3378
 
                        }
3379
 
 
3380
 
                        /* All indexes on BLOB and TEXT are column prefix
3381
 
                        indexes, and we may need to truncate the data to be
3382
 
                        stored in the key value: */
3383
 
 
3384
 
                        if (true_len > key_len) {
3385
 
                                true_len = key_len;
3386
 
                        }
3387
 
 
3388
 
                        /* MySQL reserves 2 bytes for the length and the
3389
 
                        storage of the number is little-endian */
3390
 
 
3391
 
                        innobase_write_to_2_little_endian(
3392
 
                                        (byte*)buff, true_len);
3393
 
                        buff += 2;
3394
 
 
3395
 
                        memcpy(buff, blob_data, true_len);
3396
 
 
3397
 
                        /* Note that we always reserve the maximum possible
3398
 
                        length of the BLOB prefix in the key value. */
3399
 
 
3400
 
                        buff += key_len;
3401
 
                } else {
3402
 
                        /* Here we handle all other data types except the
3403
 
                        true VARCHAR, BLOB and TEXT. Note that the column
3404
 
                        value we store may be also in a column prefix
3405
 
                        index. */
3406
 
 
3407
 
                        ulint                   true_len;
3408
 
                        ulint                   key_len;
3409
 
                        const unsigned char*            src_start;
3410
 
                        enum_field_types        real_type;
3411
 
 
3412
 
                        key_len = key_part->length;
3413
 
 
3414
 
                        if (is_null) {
3415
 
                                 buff += key_len;
3416
 
 
3417
 
                                 continue;
3418
 
                        }
3419
 
 
3420
 
                        src_start = record + key_part->offset;
3421
 
                        real_type = field->real_type();
3422
 
                        true_len = key_len;
3423
 
 
3424
 
                        /* Character set for the field is defined only
3425
 
                        to fields whose type is string and real field
3426
 
                        type is not enum or set. For these fields check
3427
 
                        if character set is multi byte. */
3428
 
 
3429
 
                        memcpy(buff, src_start, true_len);
3430
 
                        buff += true_len;
3431
 
 
3432
 
                        /* Pad the unused space with spaces. Note that no
3433
 
                        padding is ever needed for UCS-2 because in MySQL,
3434
 
                        all UCS2 characters are 2 bytes, as MySQL does not
3435
 
                        support surrogate pairs, which are needed to represent
3436
 
                        characters in the range U+10000 to U+10FFFF. */
3437
 
 
3438
 
                        if (true_len < key_len) {
3439
 
                                ulint pad_len = key_len - true_len;
3440
 
                                memset(buff, ' ', pad_len);
3441
 
                                buff += pad_len;
3442
 
                        }
3443
 
                }
3444
 
        }
3445
 
 
3446
 
        ut_a(buff <= buff_start + buff_len);
3447
 
 
3448
 
        return((uint)(buff - buff_start));
 
3220
  KEY*    key_info  = table->key_info + keynr;
 
3221
  KEY_PART_INFO*  key_part  = key_info->key_part;
 
3222
  KEY_PART_INFO*  end   = key_part + key_info->key_parts;
 
3223
  char*   buff_start  = buff;
 
3224
  enum_field_types mysql_type;
 
3225
  Field*    field;
 
3226
  ibool   is_null;
 
3227
 
 
3228
  /* The format for storing a key field in MySQL is the following:
 
3229
 
 
3230
  1. If the column can be NULL, then in the first byte we put 1 if the
 
3231
  field value is NULL, 0 otherwise.
 
3232
 
 
3233
  2. If the column is of a BLOB type (it must be a column prefix field
 
3234
  in this case), then we put the length of the data in the field to the
 
3235
  next 2 bytes, in the little-endian format. If the field is SQL NULL,
 
3236
  then these 2 bytes are set to 0. Note that the length of data in the
 
3237
  field is <= column prefix length.
 
3238
 
 
3239
  3. In a column prefix field, prefix_len next bytes are reserved for
 
3240
  data. In a normal field the max field length next bytes are reserved
 
3241
  for data. For a VARCHAR(n) the max field length is n. If the stored
 
3242
  value is the SQL NULL then these data bytes are set to 0.
 
3243
 
 
3244
  4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
 
3245
  in the MySQL row format, the length is stored in 1 or 2 bytes,
 
3246
  depending on the maximum allowed length. But in the MySQL key value
 
3247
  format, the length always takes 2 bytes.
 
3248
 
 
3249
  We have to zero-fill the buffer so that MySQL is able to use a
 
3250
  simple memcmp to compare two key values to determine if they are
 
3251
  equal. MySQL does this to compare contents of two 'ref' values. */
 
3252
 
 
3253
  bzero(buff, buff_len);
 
3254
 
 
3255
  for (; key_part != end; key_part++) {
 
3256
    is_null = FALSE;
 
3257
 
 
3258
    if (key_part->null_bit) {
 
3259
      if (record[key_part->null_offset]
 
3260
            & key_part->null_bit) {
 
3261
        *buff = 1;
 
3262
        is_null = TRUE;
 
3263
      } else {
 
3264
        *buff = 0;
 
3265
      }
 
3266
      buff++;
 
3267
    }
 
3268
 
 
3269
    field = key_part->field;
 
3270
    mysql_type = field->type();
 
3271
 
 
3272
    if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
 
3273
            /* >= 5.0.3 true VARCHAR */
 
3274
      ulint   lenlen;
 
3275
      ulint   len;
 
3276
      const byte* data;
 
3277
      ulint   key_len;
 
3278
      ulint   true_len;
 
3279
      const CHARSET_INFO* cs;
 
3280
      int   error=0;
 
3281
 
 
3282
      key_len = key_part->length;
 
3283
 
 
3284
      if (is_null) {
 
3285
        buff += key_len + 2;
 
3286
 
 
3287
        continue;
 
3288
      }
 
3289
      cs = field->charset();
 
3290
 
 
3291
      lenlen = (ulint)
 
3292
        (((Field_varstring*)field)->length_bytes);
 
3293
 
 
3294
      data = row_mysql_read_true_varchar(&len,
 
3295
        (byte*) (record
 
3296
        + (ulint)get_field_offset(table, field)),
 
3297
        lenlen);
 
3298
 
 
3299
      true_len = len;
 
3300
 
 
3301
      /* For multi byte character sets we need to calculate
 
3302
      the true length of the key */
 
3303
 
 
3304
      if (len > 0 && cs->mbmaxlen > 1) {
 
3305
        true_len = (ulint) cs->cset->well_formed_len(cs,
 
3306
            (const char *) data,
 
3307
            (const char *) data + len,
 
3308
                                                (uint) (key_len /
 
3309
                                                        cs->mbmaxlen),
 
3310
            &error);
 
3311
      }
 
3312
 
 
3313
      /* In a column prefix index, we may need to truncate
 
3314
      the stored value: */
 
3315
 
 
3316
      if (true_len > key_len) {
 
3317
        true_len = key_len;
 
3318
      }
 
3319
 
 
3320
      /* The length in a key value is always stored in 2
 
3321
      bytes */
 
3322
 
 
3323
      row_mysql_store_true_var_len((byte*)buff, true_len, 2);
 
3324
      buff += 2;
 
3325
 
 
3326
      memcpy(buff, data, true_len);
 
3327
 
 
3328
      /* Note that we always reserve the maximum possible
 
3329
      length of the true VARCHAR in the key value, though
 
3330
      only len first bytes after the 2 length bytes contain
 
3331
      actual data. The rest of the space was reset to zero
 
3332
      in the bzero() call above. */
 
3333
 
 
3334
      buff += key_len;
 
3335
 
 
3336
    } else if (mysql_type == DRIZZLE_TYPE_BLOB) {
 
3337
 
 
3338
      const CHARSET_INFO* cs;
 
3339
      ulint   key_len;
 
3340
      ulint   true_len;
 
3341
      int   error=0;
 
3342
      ulint   blob_len;
 
3343
      const byte* blob_data;
 
3344
 
 
3345
      ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
 
3346
 
 
3347
      key_len = key_part->length;
 
3348
 
 
3349
      if (is_null) {
 
3350
        buff += key_len + 2;
 
3351
 
 
3352
        continue;
 
3353
      }
 
3354
 
 
3355
      cs = field->charset();
 
3356
 
 
3357
      blob_data = row_mysql_read_blob_ref(&blob_len,
 
3358
        (byte*) (record
 
3359
        + (ulint)get_field_offset(table, field)),
 
3360
          (ulint) field->pack_length());
 
3361
 
 
3362
      true_len = blob_len;
 
3363
 
 
3364
      ut_a(get_field_offset(table, field)
 
3365
        == key_part->offset);
 
3366
 
 
3367
      /* For multi byte character sets we need to calculate
 
3368
      the true length of the key */
 
3369
 
 
3370
      if (blob_len > 0 && cs->mbmaxlen > 1) {
 
3371
        true_len = (ulint) cs->cset->well_formed_len(cs,
 
3372
            (const char *) blob_data,
 
3373
            (const char *) blob_data
 
3374
              + blob_len,
 
3375
                                                (uint) (key_len /
 
3376
                                                        cs->mbmaxlen),
 
3377
            &error);
 
3378
      }
 
3379
 
 
3380
      /* All indexes on BLOB and TEXT are column prefix
 
3381
      indexes, and we may need to truncate the data to be
 
3382
      stored in the key value: */
 
3383
 
 
3384
      if (true_len > key_len) {
 
3385
        true_len = key_len;
 
3386
      }
 
3387
 
 
3388
      /* MySQL reserves 2 bytes for the length and the
 
3389
      storage of the number is little-endian */
 
3390
 
 
3391
      innobase_write_to_2_little_endian(
 
3392
          (byte*)buff, true_len);
 
3393
      buff += 2;
 
3394
 
 
3395
      memcpy(buff, blob_data, true_len);
 
3396
 
 
3397
      /* Note that we always reserve the maximum possible
 
3398
      length of the BLOB prefix in the key value. */
 
3399
 
 
3400
      buff += key_len;
 
3401
    } else {
 
3402
      /* Here we handle all other data types except the
 
3403
      true VARCHAR, BLOB and TEXT. Note that the column
 
3404
      value we store may be also in a column prefix
 
3405
      index. */
 
3406
 
 
3407
      ulint     true_len;
 
3408
      ulint     key_len;
 
3409
      const unsigned char*    src_start;
 
3410
      enum_field_types  real_type;
 
3411
 
 
3412
      key_len = key_part->length;
 
3413
 
 
3414
      if (is_null) {
 
3415
         buff += key_len;
 
3416
 
 
3417
         continue;
 
3418
      }
 
3419
 
 
3420
      src_start = record + key_part->offset;
 
3421
      real_type = field->real_type();
 
3422
      true_len = key_len;
 
3423
 
 
3424
      /* Character set for the field is defined only
 
3425
      to fields whose type is string and real field
 
3426
      type is not enum or set. For these fields check
 
3427
      if character set is multi byte. */
 
3428
 
 
3429
      memcpy(buff, src_start, true_len);
 
3430
      buff += true_len;
 
3431
 
 
3432
      /* Pad the unused space with spaces. Note that no
 
3433
      padding is ever needed for UCS-2 because in MySQL,
 
3434
      all UCS2 characters are 2 bytes, as MySQL does not
 
3435
      support surrogate pairs, which are needed to represent
 
3436
      characters in the range U+10000 to U+10FFFF. */
 
3437
 
 
3438
      if (true_len < key_len) {
 
3439
        ulint pad_len = key_len - true_len;
 
3440
        memset(buff, ' ', pad_len);
 
3441
        buff += pad_len;
 
3442
      }
 
3443
    }
 
3444
  }
 
3445
 
 
3446
  ut_a(buff <= buff_start + buff_len);
 
3447
 
 
3448
  return((uint)(buff - buff_start));
3449
3449
}
3450
3450
 
3451
3451
/**************************************************************//**
3455
3455
void
3456
3456
build_template(
3457
3457
/*===========*/
3458
 
        row_prebuilt_t* prebuilt,       /*!< in/out: prebuilt struct */
3459
 
        Session*        ,               /*!< in: current user thread, used
3460
 
                                        only if templ_type is
3461
 
                                        ROW_DRIZZLE_REC_FIELDS */
3462
 
        Table*          table,          /*!< in: MySQL table */
3463
 
        uint            templ_type)     /*!< in: ROW_MYSQL_WHOLE_ROW or
3464
 
                                        ROW_DRIZZLE_REC_FIELDS */
 
3458
  row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct */
 
3459
  Session*  ,   /*!< in: current user thread, used
 
3460
          only if templ_type is
 
3461
          ROW_DRIZZLE_REC_FIELDS */
 
3462
  Table*    table,    /*!< in: MySQL table */
 
3463
  uint    templ_type) /*!< in: ROW_MYSQL_WHOLE_ROW or
 
3464
          ROW_DRIZZLE_REC_FIELDS */
3465
3465
{
3466
 
        dict_index_t*   index;
3467
 
        dict_index_t*   clust_index;
3468
 
        mysql_row_templ_t* templ;
3469
 
        Field*          field;
3470
 
        ulint           n_fields;
3471
 
        ulint           n_requested_fields      = 0;
3472
 
        ibool           fetch_all_in_key        = FALSE;
3473
 
        ibool           fetch_primary_key_cols  = FALSE;
3474
 
        ulint           i= 0;
3475
 
        /* byte offset of the end of last requested column */
3476
 
        ulint           mysql_prefix_len        = 0;
3477
 
 
3478
 
        if (prebuilt->select_lock_type == LOCK_X) {
3479
 
                /* We always retrieve the whole clustered index record if we
3480
 
                use exclusive row level locks, for example, if the read is
3481
 
                done in an UPDATE statement. */
3482
 
 
3483
 
                templ_type = ROW_MYSQL_WHOLE_ROW;
3484
 
        }
3485
 
 
3486
 
        if (templ_type == ROW_MYSQL_REC_FIELDS) {
3487
 
                if (prebuilt->hint_need_to_fetch_extra_cols
3488
 
                        == ROW_RETRIEVE_ALL_COLS) {
3489
 
 
3490
 
                        /* We know we must at least fetch all columns in the
3491
 
                        key, or all columns in the table */
3492
 
 
3493
 
                        if (prebuilt->read_just_key) {
3494
 
                                /* MySQL has instructed us that it is enough
3495
 
                                to fetch the columns in the key; looks like
3496
 
                                MySQL can set this flag also when there is
3497
 
                                only a prefix of the column in the key: in
3498
 
                                that case we retrieve the whole column from
3499
 
                                the clustered index */
3500
 
 
3501
 
                                fetch_all_in_key = TRUE;
3502
 
                        } else {
3503
 
                                templ_type = ROW_MYSQL_WHOLE_ROW;
3504
 
                        }
3505
 
                } else if (prebuilt->hint_need_to_fetch_extra_cols
3506
 
                        == ROW_RETRIEVE_PRIMARY_KEY) {
3507
 
                        /* We must at least fetch all primary key cols. Note
3508
 
                           that if the clustered index was internally generated
3509
 
                           by InnoDB on the row id (no primary key was
3510
 
                           defined), then row_search_for_mysql() will always
3511
 
                           retrieve the row id to a special buffer in the
3512
 
                           prebuilt struct. */
3513
 
 
3514
 
                        fetch_primary_key_cols = TRUE;
3515
 
                }
3516
 
        }
3517
 
 
3518
 
        clust_index = dict_table_get_first_index(prebuilt->table);
3519
 
 
3520
 
        if (templ_type == ROW_MYSQL_REC_FIELDS) {
3521
 
                index = prebuilt->index;
3522
 
        } else {
3523
 
                index = clust_index;
3524
 
        }
3525
 
 
3526
 
        if (index == clust_index) {
3527
 
                prebuilt->need_to_access_clustered = TRUE;
3528
 
        } else {
3529
 
                prebuilt->need_to_access_clustered = FALSE;
3530
 
                /* Below we check column by column if we need to access
3531
 
                the clustered index */
3532
 
        }
3533
 
 
3534
 
        n_fields = (ulint)table->s->fields; /* number of columns */
3535
 
 
3536
 
        if (!prebuilt->mysql_template) {
3537
 
                prebuilt->mysql_template = (mysql_row_templ_t*)
3538
 
                        mem_alloc(n_fields * sizeof(mysql_row_templ_t));
3539
 
        }
3540
 
 
3541
 
        prebuilt->template_type = templ_type;
3542
 
        prebuilt->null_bitmap_len = table->s->null_bytes;
3543
 
 
3544
 
        prebuilt->templ_contains_blob = FALSE;
3545
 
 
3546
 
        /* Note that in InnoDB, i is the column number. MySQL calls columns
3547
 
        'fields'. */
3548
 
        for (i = 0; i < n_fields; i++) {
3549
 
                templ = prebuilt->mysql_template + n_requested_fields;
3550
 
                field = table->field[i];
3551
 
 
3552
 
                if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
3553
 
                        /* Decide which columns we should fetch
3554
 
                        and which we can skip. */
3555
 
                        register const ibool    index_contains_field =
3556
 
                                dict_index_contains_col_or_prefix(index, i);
3557
 
 
3558
 
                        if (!index_contains_field && prebuilt->read_just_key) {
3559
 
                                /* If this is a 'key read', we do not need
3560
 
                                columns that are not in the key */
3561
 
 
3562
 
                                goto skip_field;
3563
 
                        }
3564
 
 
3565
 
                        if (index_contains_field && fetch_all_in_key) {
3566
 
                                /* This field is needed in the query */
3567
 
 
3568
 
                                goto include_field;
3569
 
                        }
 
3466
  dict_index_t* index;
 
3467
  dict_index_t* clust_index;
 
3468
  mysql_row_templ_t* templ;
 
3469
  Field*    field;
 
3470
  ulint   n_fields;
 
3471
  ulint   n_requested_fields  = 0;
 
3472
  ibool   fetch_all_in_key  = FALSE;
 
3473
  ibool   fetch_primary_key_cols  = FALSE;
 
3474
  ulint   i= 0;
 
3475
  /* byte offset of the end of last requested column */
 
3476
  ulint   mysql_prefix_len  = 0;
 
3477
 
 
3478
  if (prebuilt->select_lock_type == LOCK_X) {
 
3479
    /* We always retrieve the whole clustered index record if we
 
3480
    use exclusive row level locks, for example, if the read is
 
3481
    done in an UPDATE statement. */
 
3482
 
 
3483
    templ_type = ROW_MYSQL_WHOLE_ROW;
 
3484
  }
 
3485
 
 
3486
  if (templ_type == ROW_MYSQL_REC_FIELDS) {
 
3487
    if (prebuilt->hint_need_to_fetch_extra_cols
 
3488
      == ROW_RETRIEVE_ALL_COLS) {
 
3489
 
 
3490
      /* We know we must at least fetch all columns in the
 
3491
      key, or all columns in the table */
 
3492
 
 
3493
      if (prebuilt->read_just_key) {
 
3494
        /* MySQL has instructed us that it is enough
 
3495
        to fetch the columns in the key; looks like
 
3496
        MySQL can set this flag also when there is
 
3497
        only a prefix of the column in the key: in
 
3498
        that case we retrieve the whole column from
 
3499
        the clustered index */
 
3500
 
 
3501
        fetch_all_in_key = TRUE;
 
3502
      } else {
 
3503
        templ_type = ROW_MYSQL_WHOLE_ROW;
 
3504
      }
 
3505
    } else if (prebuilt->hint_need_to_fetch_extra_cols
 
3506
      == ROW_RETRIEVE_PRIMARY_KEY) {
 
3507
      /* We must at least fetch all primary key cols. Note
 
3508
         that if the clustered index was internally generated
 
3509
         by InnoDB on the row id (no primary key was
 
3510
         defined), then row_search_for_mysql() will always
 
3511
         retrieve the row id to a special buffer in the
 
3512
         prebuilt struct. */
 
3513
 
 
3514
      fetch_primary_key_cols = TRUE;
 
3515
    }
 
3516
  }
 
3517
 
 
3518
  clust_index = dict_table_get_first_index(prebuilt->table);
 
3519
 
 
3520
  if (templ_type == ROW_MYSQL_REC_FIELDS) {
 
3521
    index = prebuilt->index;
 
3522
  } else {
 
3523
    index = clust_index;
 
3524
  }
 
3525
 
 
3526
  if (index == clust_index) {
 
3527
    prebuilt->need_to_access_clustered = TRUE;
 
3528
  } else {
 
3529
    prebuilt->need_to_access_clustered = FALSE;
 
3530
    /* Below we check column by column if we need to access
 
3531
    the clustered index */
 
3532
  }
 
3533
 
 
3534
  n_fields = (ulint)table->s->fields; /* number of columns */
 
3535
 
 
3536
  if (!prebuilt->mysql_template) {
 
3537
    prebuilt->mysql_template = (mysql_row_templ_t*)
 
3538
      mem_alloc(n_fields * sizeof(mysql_row_templ_t));
 
3539
  }
 
3540
 
 
3541
  prebuilt->template_type = templ_type;
 
3542
  prebuilt->null_bitmap_len = table->s->null_bytes;
 
3543
 
 
3544
  prebuilt->templ_contains_blob = FALSE;
 
3545
 
 
3546
  /* Note that in InnoDB, i is the column number. MySQL calls columns
 
3547
  'fields'. */
 
3548
  for (i = 0; i < n_fields; i++) {
 
3549
    templ = prebuilt->mysql_template + n_requested_fields;
 
3550
    field = table->field[i];
 
3551
 
 
3552
    if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
 
3553
      /* Decide which columns we should fetch
 
3554
      and which we can skip. */
 
3555
      register const ibool  index_contains_field =
 
3556
        dict_index_contains_col_or_prefix(index, i);
 
3557
 
 
3558
      if (!index_contains_field && prebuilt->read_just_key) {
 
3559
        /* If this is a 'key read', we do not need
 
3560
        columns that are not in the key */
 
3561
 
 
3562
        goto skip_field;
 
3563
      }
 
3564
 
 
3565
      if (index_contains_field && fetch_all_in_key) {
 
3566
        /* This field is needed in the query */
 
3567
 
 
3568
        goto include_field;
 
3569
      }
3570
3570
 
3571
3571
                        if (field->isReadSet() || field->isWriteSet())
3572
 
                                /* This field is needed in the query */
3573
 
                                goto include_field;
 
3572
        /* This field is needed in the query */
 
3573
        goto include_field;
3574
3574
 
3575
3575
                        assert(table->isReadSet(i) == field->isReadSet());
3576
3576
                        assert(table->isWriteSet(i) == field->isWriteSet());
3577
3577
 
3578
 
                        if (fetch_primary_key_cols
3579
 
                                && dict_table_col_in_clustered_key(
3580
 
                                        index->table, i)) {
3581
 
                                /* This field is needed in the query */
3582
 
 
3583
 
                                goto include_field;
3584
 
                        }
3585
 
 
3586
 
                        /* This field is not needed in the query, skip it */
3587
 
 
3588
 
                        goto skip_field;
3589
 
                }
 
3578
      if (fetch_primary_key_cols
 
3579
        && dict_table_col_in_clustered_key(
 
3580
          index->table, i)) {
 
3581
        /* This field is needed in the query */
 
3582
 
 
3583
        goto include_field;
 
3584
      }
 
3585
 
 
3586
      /* This field is not needed in the query, skip it */
 
3587
 
 
3588
      goto skip_field;
 
3589
    }
3590
3590
include_field:
3591
 
                n_requested_fields++;
3592
 
 
3593
 
                templ->col_no = i;
3594
 
 
3595
 
                if (index == clust_index) {
3596
 
                        templ->rec_field_no = dict_col_get_clust_pos(
3597
 
                                &index->table->cols[i], index);
3598
 
                } else {
3599
 
                        templ->rec_field_no = dict_index_get_nth_col_pos(
3600
 
                                                                index, i);
3601
 
                }
3602
 
 
3603
 
                if (templ->rec_field_no == ULINT_UNDEFINED) {
3604
 
                        prebuilt->need_to_access_clustered = TRUE;
3605
 
                }
3606
 
 
3607
 
                if (field->null_ptr) {
3608
 
                        templ->mysql_null_byte_offset =
3609
 
                                (ulint) ((char*) field->null_ptr
3610
 
                                        - (char*) table->record[0]);
3611
 
 
3612
 
                        templ->mysql_null_bit_mask = (ulint) field->null_bit;
3613
 
                } else {
3614
 
                        templ->mysql_null_bit_mask = 0;
3615
 
                }
3616
 
 
3617
 
                templ->mysql_col_offset = (ulint)
3618
 
                                        get_field_offset(table, field);
3619
 
 
3620
 
                templ->mysql_col_len = (ulint) field->pack_length();
3621
 
                if (mysql_prefix_len < templ->mysql_col_offset
3622
 
                                + templ->mysql_col_len) {
3623
 
                        mysql_prefix_len = templ->mysql_col_offset
3624
 
                                + templ->mysql_col_len;
3625
 
                }
3626
 
                templ->type = index->table->cols[i].mtype;
3627
 
                templ->mysql_type = (ulint)field->type();
3628
 
 
3629
 
                if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
3630
 
                        templ->mysql_length_bytes = (ulint)
3631
 
                                (((Field_varstring*)field)->length_bytes);
3632
 
                }
3633
 
 
3634
 
                templ->charset = dtype_get_charset_coll(
3635
 
                        index->table->cols[i].prtype);
3636
 
                templ->mbminlen = index->table->cols[i].mbminlen;
3637
 
                templ->mbmaxlen = index->table->cols[i].mbmaxlen;
3638
 
                templ->is_unsigned = index->table->cols[i].prtype
3639
 
                                                        & DATA_UNSIGNED;
3640
 
                if (templ->type == DATA_BLOB) {
3641
 
                        prebuilt->templ_contains_blob = TRUE;
3642
 
                }
 
3591
    n_requested_fields++;
 
3592
 
 
3593
    templ->col_no = i;
 
3594
 
 
3595
    if (index == clust_index) {
 
3596
      templ->rec_field_no = dict_col_get_clust_pos(
 
3597
        &index->table->cols[i], index);
 
3598
    } else {
 
3599
      templ->rec_field_no = dict_index_get_nth_col_pos(
 
3600
                index, i);
 
3601
    }
 
3602
 
 
3603
    if (templ->rec_field_no == ULINT_UNDEFINED) {
 
3604
      prebuilt->need_to_access_clustered = TRUE;
 
3605
    }
 
3606
 
 
3607
    if (field->null_ptr) {
 
3608
      templ->mysql_null_byte_offset =
 
3609
        (ulint) ((char*) field->null_ptr
 
3610
          - (char*) table->record[0]);
 
3611
 
 
3612
      templ->mysql_null_bit_mask = (ulint) field->null_bit;
 
3613
    } else {
 
3614
      templ->mysql_null_bit_mask = 0;
 
3615
    }
 
3616
 
 
3617
    templ->mysql_col_offset = (ulint)
 
3618
          get_field_offset(table, field);
 
3619
 
 
3620
    templ->mysql_col_len = (ulint) field->pack_length();
 
3621
    if (mysql_prefix_len < templ->mysql_col_offset
 
3622
        + templ->mysql_col_len) {
 
3623
      mysql_prefix_len = templ->mysql_col_offset
 
3624
        + templ->mysql_col_len;
 
3625
    }
 
3626
    templ->type = index->table->cols[i].mtype;
 
3627
    templ->mysql_type = (ulint)field->type();
 
3628
 
 
3629
    if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
 
3630
      templ->mysql_length_bytes = (ulint)
 
3631
        (((Field_varstring*)field)->length_bytes);
 
3632
    }
 
3633
 
 
3634
    templ->charset = dtype_get_charset_coll(
 
3635
      index->table->cols[i].prtype);
 
3636
    templ->mbminlen = index->table->cols[i].mbminlen;
 
3637
    templ->mbmaxlen = index->table->cols[i].mbmaxlen;
 
3638
    templ->is_unsigned = index->table->cols[i].prtype
 
3639
              & DATA_UNSIGNED;
 
3640
    if (templ->type == DATA_BLOB) {
 
3641
      prebuilt->templ_contains_blob = TRUE;
 
3642
    }
3643
3643
skip_field:
3644
 
                ;
3645
 
        }
3646
 
 
3647
 
        prebuilt->n_template = n_requested_fields;
3648
 
        prebuilt->mysql_prefix_len = mysql_prefix_len;
3649
 
 
3650
 
        if (index != clust_index && prebuilt->need_to_access_clustered) {
3651
 
                /* Change rec_field_no's to correspond to the clustered index
3652
 
                record */
3653
 
                for (i = 0; i < n_requested_fields; i++) {
3654
 
                        templ = prebuilt->mysql_template + i;
3655
 
 
3656
 
                        templ->rec_field_no = dict_col_get_clust_pos(
3657
 
                                &index->table->cols[templ->col_no],
3658
 
                                clust_index);
3659
 
                }
3660
 
        }
 
3644
    ;
 
3645
  }
 
3646
 
 
3647
  prebuilt->n_template = n_requested_fields;
 
3648
  prebuilt->mysql_prefix_len = mysql_prefix_len;
 
3649
 
 
3650
  if (index != clust_index && prebuilt->need_to_access_clustered) {
 
3651
    /* Change rec_field_no's to correspond to the clustered index
 
3652
    record */
 
3653
    for (i = 0; i < n_requested_fields; i++) {
 
3654
      templ = prebuilt->mysql_template + i;
 
3655
 
 
3656
      templ->rec_field_no = dict_col_get_clust_pos(
 
3657
        &index->table->cols[templ->col_no],
 
3658
        clust_index);
 
3659
    }
 
3660
  }
3661
3661
}
3662
3662
 
3663
3663
/********************************************************************//**
3666
3666
uint64_t
3667
3667
ha_innobase::innobase_get_int_col_max_value(
3668
3668
/*========================================*/
3669
 
        const Field*    field)
 
3669
  const Field*  field)
3670
3670
{
3671
 
        uint64_t        max_value = 0;
3672
 
 
3673
 
        switch(field->key_type()) {
3674
 
        /* TINY */
3675
 
        case HA_KEYTYPE_BINARY:
3676
 
                max_value = 0xFFULL;
3677
 
                break;
3678
 
        /* MEDIUM */
3679
 
        case HA_KEYTYPE_UINT24:
3680
 
                max_value = 0xFFFFFFULL;
3681
 
                break;
3682
 
        /* LONG */
3683
 
        case HA_KEYTYPE_ULONG_INT:
3684
 
                max_value = 0xFFFFFFFFULL;
3685
 
                break;
3686
 
        case HA_KEYTYPE_LONG_INT:
3687
 
                max_value = 0x7FFFFFFFULL;
3688
 
                break;
3689
 
        /* BIG */
3690
 
        case HA_KEYTYPE_ULONGLONG:
3691
 
                max_value = 0xFFFFFFFFFFFFFFFFULL;
3692
 
                break;
3693
 
        case HA_KEYTYPE_LONGLONG:
3694
 
                max_value = 0x7FFFFFFFFFFFFFFFULL;
3695
 
                break;
3696
 
        case HA_KEYTYPE_DOUBLE:
3697
 
                /* We use the maximum as per IEEE754-2008 standard, 2^53 */
3698
 
                max_value = 0x20000000000000ULL;
3699
 
                break;
3700
 
        default:
3701
 
                ut_error;
3702
 
        }
3703
 
 
3704
 
        return(max_value);
 
3671
  uint64_t  max_value = 0;
 
3672
 
 
3673
  switch(field->key_type()) {
 
3674
  /* TINY */
 
3675
  case HA_KEYTYPE_BINARY:
 
3676
    max_value = 0xFFULL;
 
3677
    break;
 
3678
  /* MEDIUM */
 
3679
  case HA_KEYTYPE_UINT24:
 
3680
    max_value = 0xFFFFFFULL;
 
3681
    break;
 
3682
  /* LONG */
 
3683
  case HA_KEYTYPE_ULONG_INT:
 
3684
    max_value = 0xFFFFFFFFULL;
 
3685
    break;
 
3686
  case HA_KEYTYPE_LONG_INT:
 
3687
    max_value = 0x7FFFFFFFULL;
 
3688
    break;
 
3689
  /* BIG */
 
3690
  case HA_KEYTYPE_ULONGLONG:
 
3691
    max_value = 0xFFFFFFFFFFFFFFFFULL;
 
3692
    break;
 
3693
  case HA_KEYTYPE_LONGLONG:
 
3694
    max_value = 0x7FFFFFFFFFFFFFFFULL;
 
3695
    break;
 
3696
  case HA_KEYTYPE_DOUBLE:
 
3697
    /* We use the maximum as per IEEE754-2008 standard, 2^53 */
 
3698
    max_value = 0x20000000000000ULL;
 
3699
    break;
 
3700
  default:
 
3701
    ut_error;
 
3702
  }
 
3703
 
 
3704
  return(max_value);
3705
3705
}
3706
3706
 
3707
3707
/********************************************************************//**
3710
3710
INSERT ... SELECT type of statements, since MySQL binlog only stores the
3711
3711
min value of the autoinc interval. Once that is fixed we can get rid of
3712
3712
the special lock handling.
3713
 
@return DB_SUCCESS if all OK else error code */
 
3713
@return DB_SUCCESS if all OK else error code */
3714
3714
UNIV_INTERN
3715
3715
ulint
3716
3716
ha_innobase::innobase_lock_autoinc(void)
3717
3717
/*====================================*/
3718
3718
{
3719
 
        ulint           error = DB_SUCCESS;
3720
 
 
3721
 
        switch (innobase_autoinc_lock_mode) {
3722
 
        case AUTOINC_NO_LOCKING:
3723
 
                /* Acquire only the AUTOINC mutex. */
3724
 
                dict_table_autoinc_lock(prebuilt->table);
3725
 
                break;
3726
 
 
3727
 
        case AUTOINC_NEW_STYLE_LOCKING:
3728
 
                /* For simple (single/multi) row INSERTs, we fallback to the
3729
 
                old style only if another transaction has already acquired
3730
 
                the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
3731
 
                etc. type of statement. */
3732
 
                if (session_sql_command(user_session) == SQLCOM_INSERT
3733
 
                    || session_sql_command(user_session) == SQLCOM_REPLACE) {
3734
 
                        dict_table_t*   d_table = prebuilt->table;
3735
 
 
3736
 
                        /* Acquire the AUTOINC mutex. */
3737
 
                        dict_table_autoinc_lock(d_table);
3738
 
 
3739
 
                        /* We need to check that another transaction isn't
3740
 
                        already holding the AUTOINC lock on the table. */
3741
 
                        if (d_table->n_waiting_or_granted_auto_inc_locks) {
3742
 
                                /* Release the mutex to avoid deadlocks. */
3743
 
                                dict_table_autoinc_unlock(d_table);
3744
 
                        } else {
3745
 
                                break;
3746
 
                        }
3747
 
                }
3748
 
                /* Fall through to old style locking. */
3749
 
 
3750
 
        case AUTOINC_OLD_STYLE_LOCKING:
3751
 
                error = row_lock_table_autoinc_for_mysql(prebuilt);
3752
 
 
3753
 
                if (error == DB_SUCCESS) {
3754
 
 
3755
 
                        /* Acquire the AUTOINC mutex. */
3756
 
                        dict_table_autoinc_lock(prebuilt->table);
3757
 
                }
3758
 
                break;
3759
 
 
3760
 
        default:
3761
 
                ut_error;
3762
 
        }
3763
 
 
3764
 
        return(ulong(error));
 
3719
  ulint   error = DB_SUCCESS;
 
3720
 
 
3721
  switch (innobase_autoinc_lock_mode) {
 
3722
  case AUTOINC_NO_LOCKING:
 
3723
    /* Acquire only the AUTOINC mutex. */
 
3724
    dict_table_autoinc_lock(prebuilt->table);
 
3725
    break;
 
3726
 
 
3727
  case AUTOINC_NEW_STYLE_LOCKING:
 
3728
    /* For simple (single/multi) row INSERTs, we fallback to the
 
3729
    old style only if another transaction has already acquired
 
3730
    the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
 
3731
    etc. type of statement. */
 
3732
    if (session_sql_command(user_session) == SQLCOM_INSERT
 
3733
        || session_sql_command(user_session) == SQLCOM_REPLACE) {
 
3734
      dict_table_t* d_table = prebuilt->table;
 
3735
 
 
3736
      /* Acquire the AUTOINC mutex. */
 
3737
      dict_table_autoinc_lock(d_table);
 
3738
 
 
3739
      /* We need to check that another transaction isn't
 
3740
      already holding the AUTOINC lock on the table. */
 
3741
      if (d_table->n_waiting_or_granted_auto_inc_locks) {
 
3742
        /* Release the mutex to avoid deadlocks. */
 
3743
        dict_table_autoinc_unlock(d_table);
 
3744
      } else {
 
3745
        break;
 
3746
      }
 
3747
    }
 
3748
    /* Fall through to old style locking. */
 
3749
 
 
3750
  case AUTOINC_OLD_STYLE_LOCKING:
 
3751
    error = row_lock_table_autoinc_for_mysql(prebuilt);
 
3752
 
 
3753
    if (error == DB_SUCCESS) {
 
3754
 
 
3755
      /* Acquire the AUTOINC mutex. */
 
3756
      dict_table_autoinc_lock(prebuilt->table);
 
3757
    }
 
3758
    break;
 
3759
 
 
3760
  default:
 
3761
    ut_error;
 
3762
  }
 
3763
 
 
3764
  return(ulong(error));
3765
3765
}
3766
3766
 
3767
3767
/********************************************************************//**
3768
3768
Reset the autoinc value in the table.
3769
 
@return DB_SUCCESS if all went well else error code */
 
3769
@return DB_SUCCESS if all went well else error code */
3770
3770
UNIV_INTERN
3771
3771
ulint
3772
3772
ha_innobase::innobase_reset_autoinc(
3773
3773
/*================================*/
3774
 
        uint64_t        autoinc)        /*!< in: value to store */
 
3774
  uint64_t  autoinc)  /*!< in: value to store */
3775
3775
{
3776
 
        ulint           error;
3777
 
 
3778
 
        error = innobase_lock_autoinc();
3779
 
 
3780
 
        if (error == DB_SUCCESS) {
3781
 
 
3782
 
                dict_table_autoinc_initialize(prebuilt->table, autoinc);
3783
 
 
3784
 
                dict_table_autoinc_unlock(prebuilt->table);
3785
 
        }
3786
 
 
3787
 
        return(ulong(error));
 
3776
  ulint   error;
 
3777
 
 
3778
  error = innobase_lock_autoinc();
 
3779
 
 
3780
  if (error == DB_SUCCESS) {
 
3781
 
 
3782
    dict_table_autoinc_initialize(prebuilt->table, autoinc);
 
3783
 
 
3784
    dict_table_autoinc_unlock(prebuilt->table);
 
3785
  }
 
3786
 
 
3787
  return(ulong(error));
3788
3788
}
3789
3789
 
3790
3790
/********************************************************************//**
3791
3791
Store the autoinc value in the table. The autoinc value is only set if
3792
3792
it's greater than the existing autoinc value in the table.
3793
 
@return DB_SUCCESS if all went well else error code */
 
3793
@return DB_SUCCESS if all went well else error code */
3794
3794
UNIV_INTERN
3795
3795
ulint
3796
3796
ha_innobase::innobase_set_max_autoinc(
3797
3797
/*==================================*/
3798
 
        uint64_t        auto_inc)       /*!< in: value to store */
 
3798
  uint64_t  auto_inc) /*!< in: value to store */
3799
3799
{
3800
 
        ulint           error;
3801
 
 
3802
 
        error = innobase_lock_autoinc();
3803
 
 
3804
 
        if (error == DB_SUCCESS) {
3805
 
 
3806
 
                dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
3807
 
 
3808
 
                dict_table_autoinc_unlock(prebuilt->table);
3809
 
        }
3810
 
 
3811
 
        return(ulong(error));
 
3800
  ulint   error;
 
3801
 
 
3802
  error = innobase_lock_autoinc();
 
3803
 
 
3804
  if (error == DB_SUCCESS) {
 
3805
 
 
3806
    dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
 
3807
 
 
3808
    dict_table_autoinc_unlock(prebuilt->table);
 
3809
  }
 
3810
 
 
3811
  return(ulong(error));
3812
3812
}
3813
3813
 
3814
3814
/********************************************************************//**
3815
3815
Stores a row in an InnoDB database, to the table specified in this
3816
3816
handle.
3817
 
@return error code */
 
3817
@return error code */
3818
3818
UNIV_INTERN
3819
3819
int
3820
3820
ha_innobase::write_row(
3821
3821
/*===================*/
3822
 
        unsigned char*  record) /*!< in: a row in MySQL format */
 
3822
  unsigned char*  record) /*!< in: a row in MySQL format */
3823
3823
{
3824
 
        ulint           error = 0;
 
3824
  ulint   error = 0;
3825
3825
        int             error_result= 0;
3826
 
        ibool           auto_inc_used= FALSE;
3827
 
        ulint           sql_command;
3828
 
        trx_t*          trx = session_to_trx(user_session);
3829
 
 
3830
 
        if (prebuilt->trx != trx) {
3831
 
          errmsg_printf(ERRMSG_LVL_ERROR, "The transaction object for the table handle is at "
3832
 
                          "%p, but for the current thread it is at %p",
3833
 
                          (const void*) prebuilt->trx, (const void*) trx);
3834
 
 
3835
 
                fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
3836
 
                ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
3837
 
                fputs("\n"
3838
 
                        "InnoDB: Dump of 200 bytes around ha_data: ",
3839
 
                        stderr);
3840
 
                ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
3841
 
                putc('\n', stderr);
3842
 
                ut_error;
3843
 
        }
3844
 
 
3845
 
        ha_statistic_increment(&system_status_var::ha_write_count);
3846
 
 
3847
 
        sql_command = session_sql_command(user_session);
3848
 
 
3849
 
        if ((sql_command == SQLCOM_ALTER_TABLE
3850
 
             || sql_command == SQLCOM_CREATE_INDEX
3851
 
             || sql_command == SQLCOM_DROP_INDEX)
3852
 
            && num_write_row >= 10000) {
3853
 
                /* ALTER TABLE is COMMITted at every 10000 copied rows.
3854
 
                The IX table lock for the original table has to be re-issued.
3855
 
                As this method will be called on a temporary table where the
3856
 
                contents of the original table is being copied to, it is
3857
 
                a bit tricky to determine the source table.  The cursor
3858
 
                position in the source table need not be adjusted after the
3859
 
                intermediate COMMIT, since writes by other transactions are
3860
 
                being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
3861
 
 
3862
 
                dict_table_t*   src_table;
3863
 
                enum lock_mode  mode;
3864
 
 
3865
 
                num_write_row = 0;
3866
 
 
3867
 
                /* Commit the transaction.  This will release the table
3868
 
                locks, so they have to be acquired again. */
3869
 
 
3870
 
                /* Altering an InnoDB table */
3871
 
                /* Get the source table. */
3872
 
                src_table = lock_get_src_table(
3873
 
                                prebuilt->trx, prebuilt->table, &mode);
3874
 
                if (!src_table) {
 
3826
  ibool   auto_inc_used= FALSE;
 
3827
  ulint   sql_command;
 
3828
  trx_t*    trx = session_to_trx(user_session);
 
3829
 
 
3830
  if (prebuilt->trx != trx) {
 
3831
    errmsg_printf(ERRMSG_LVL_ERROR, "The transaction object for the table handle is at "
 
3832
        "%p, but for the current thread it is at %p",
 
3833
        (const void*) prebuilt->trx, (const void*) trx);
 
3834
 
 
3835
    fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
 
3836
    ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
 
3837
    fputs("\n"
 
3838
      "InnoDB: Dump of 200 bytes around ha_data: ",
 
3839
      stderr);
 
3840
    ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
 
3841
    putc('\n', stderr);
 
3842
    ut_error;
 
3843
  }
 
3844
 
 
3845
  ha_statistic_increment(&system_status_var::ha_write_count);
 
3846
 
 
3847
  sql_command = session_sql_command(user_session);
 
3848
 
 
3849
  if ((sql_command == SQLCOM_ALTER_TABLE
 
3850
       || sql_command == SQLCOM_CREATE_INDEX
 
3851
       || sql_command == SQLCOM_DROP_INDEX)
 
3852
      && num_write_row >= 10000) {
 
3853
    /* ALTER TABLE is COMMITted at every 10000 copied rows.
 
3854
    The IX table lock for the original table has to be re-issued.
 
3855
    As this method will be called on a temporary table where the
 
3856
    contents of the original table is being copied to, it is
 
3857
    a bit tricky to determine the source table.  The cursor
 
3858
    position in the source table need not be adjusted after the
 
3859
    intermediate COMMIT, since writes by other transactions are
 
3860
    being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
 
3861
 
 
3862
    dict_table_t* src_table;
 
3863
    enum lock_mode  mode;
 
3864
 
 
3865
    num_write_row = 0;
 
3866
 
 
3867
    /* Commit the transaction.  This will release the table
 
3868
    locks, so they have to be acquired again. */
 
3869
 
 
3870
    /* Altering an InnoDB table */
 
3871
    /* Get the source table. */
 
3872
    src_table = lock_get_src_table(
 
3873
        prebuilt->trx, prebuilt->table, &mode);
 
3874
    if (!src_table) {
3875
3875
no_commit:
3876
 
                        /* Unknown situation: do not commit */
3877
 
                        /*
3878
 
                        ut_print_timestamp(stderr);
3879
 
                        fprintf(stderr,
3880
 
                                "  InnoDB: ALTER TABLE is holding lock"
3881
 
                                " on %lu tables!\n",
3882
 
                                prebuilt->trx->mysql_n_tables_locked);
3883
 
                        */
3884
 
                        ;
3885
 
                } else if (src_table == prebuilt->table) {
3886
 
                        /* Source table is not in InnoDB format:
3887
 
                        no need to re-acquire locks on it. */
3888
 
 
3889
 
                        /* Altering to InnoDB format */
3890
 
                        getTransactionalEngine()->commit(user_session, 1);
3891
 
                        /* We will need an IX lock on the destination table. */
3892
 
                        prebuilt->sql_stat_start = TRUE;
3893
 
                } else {
3894
 
                        /* Ensure that there are no other table locks than
3895
 
                        LOCK_IX and LOCK_AUTO_INC on the destination table. */
3896
 
 
3897
 
                        if (!lock_is_table_exclusive(prebuilt->table,
3898
 
                                                        prebuilt->trx)) {
3899
 
                                goto no_commit;
3900
 
                        }
3901
 
 
3902
 
                        /* Commit the transaction.  This will release the table
3903
 
                        locks, so they have to be acquired again. */
3904
 
                        getTransactionalEngine()->commit(user_session, 1);
3905
 
                        /* Re-acquire the table lock on the source table. */
3906
 
                        row_lock_table_for_mysql(prebuilt, src_table, mode);
3907
 
                        /* We will need an IX lock on the destination table. */
3908
 
                        prebuilt->sql_stat_start = TRUE;
3909
 
                }
3910
 
        }
3911
 
 
3912
 
        num_write_row++;
3913
 
 
3914
 
        /* This is the case where the table has an auto-increment column */
3915
 
        if (table->next_number_field && record == table->record[0]) {
3916
 
 
3917
 
                /* Reset the error code before calling
3918
 
                innobase_get_auto_increment(). */
3919
 
                prebuilt->autoinc_error = DB_SUCCESS;
3920
 
 
3921
 
                if ((error = update_auto_increment())) {
3922
 
 
3923
 
                        /* We don't want to mask autoinc overflow errors. */
3924
 
                        if (prebuilt->autoinc_error != DB_SUCCESS) {
3925
 
                                error = (int) prebuilt->autoinc_error;
3926
 
 
3927
 
                                goto report_error;
3928
 
                        }
3929
 
 
3930
 
                        /* MySQL errors are passed straight back. */
3931
 
                        error_result = (int) error;
3932
 
                        goto func_exit;
3933
 
                }
3934
 
 
3935
 
                auto_inc_used = TRUE;
3936
 
        }
3937
 
 
3938
 
        if (prebuilt->mysql_template == NULL
3939
 
            || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
3940
 
 
3941
 
                /* Build the template used in converting quickly between
3942
 
                the two database formats */
3943
 
 
3944
 
                build_template(prebuilt, NULL, table,
3945
 
                               ROW_MYSQL_WHOLE_ROW);
3946
 
        }
3947
 
 
3948
 
        innodb_srv_conc_enter_innodb(prebuilt->trx);
3949
 
 
3950
 
        error = row_insert_for_mysql((byte*) record, prebuilt);
3951
 
 
3952
 
        /* Handle duplicate key errors */
3953
 
        if (auto_inc_used) {
3954
 
                ulint           err;
3955
 
                uint64_t        auto_inc;
3956
 
                uint64_t        col_max_value;
3957
 
 
3958
 
                /* Note the number of rows processed for this statement, used
3959
 
                by get_auto_increment() to determine the number of AUTO-INC
3960
 
                values to reserve. This is only useful for a mult-value INSERT
3961
 
                and is a statement level counter.*/
3962
 
                if (trx->n_autoinc_rows > 0) {
3963
 
                        --trx->n_autoinc_rows;
3964
 
                }
3965
 
 
3966
 
                /* We need the upper limit of the col type to check for
3967
 
                whether we update the table autoinc counter or not. */
3968
 
                col_max_value = innobase_get_int_col_max_value(
3969
 
                        table->next_number_field);
3970
 
 
3971
 
                /* Get the value that MySQL attempted to store in the table.*/
3972
 
                auto_inc = table->next_number_field->val_int();
3973
 
 
3974
 
                switch (error) {
3975
 
                case DB_DUPLICATE_KEY:
3976
 
 
3977
 
                        /* A REPLACE command and LOAD DATA INFILE REPLACE
3978
 
                        handle a duplicate key error themselves, but we
3979
 
                        must update the autoinc counter if we are performing
3980
 
                        those statements. */
3981
 
 
3982
 
                        switch (sql_command) {
3983
 
                        case SQLCOM_LOAD:
3984
 
                                if ((trx->duplicates
3985
 
                                    & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
3986
 
 
3987
 
                                        goto set_max_autoinc;
3988
 
                                }
3989
 
                                break;
3990
 
 
3991
 
                        case SQLCOM_REPLACE:
3992
 
                        case SQLCOM_INSERT_SELECT:
3993
 
                        case SQLCOM_REPLACE_SELECT:
3994
 
                                goto set_max_autoinc;
3995
 
 
3996
 
                        default:
3997
 
                                break;
3998
 
                        }
3999
 
 
4000
 
                        break;
4001
 
 
4002
 
                case DB_SUCCESS:
4003
 
                        /* If the actual value inserted is greater than
4004
 
                        the upper limit of the interval, then we try and
4005
 
                        update the table upper limit. Note: last_value
4006
 
                        will be 0 if get_auto_increment() was not called.*/
4007
 
 
4008
 
                        if (auto_inc <= col_max_value
4009
 
                            && auto_inc >= prebuilt->autoinc_last_value) {
 
3876
      /* Unknown situation: do not commit */
 
3877
      /*
 
3878
      ut_print_timestamp(stderr);
 
3879
      fprintf(stderr,
 
3880
        "  InnoDB: ALTER TABLE is holding lock"
 
3881
        " on %lu tables!\n",
 
3882
        prebuilt->trx->mysql_n_tables_locked);
 
3883
      */
 
3884
      ;
 
3885
    } else if (src_table == prebuilt->table) {
 
3886
      /* Source table is not in InnoDB format:
 
3887
      no need to re-acquire locks on it. */
 
3888
 
 
3889
      /* Altering to InnoDB format */
 
3890
      getTransactionalEngine()->commit(user_session, 1);
 
3891
      /* We will need an IX lock on the destination table. */
 
3892
      prebuilt->sql_stat_start = TRUE;
 
3893
    } else {
 
3894
      /* Ensure that there are no other table locks than
 
3895
      LOCK_IX and LOCK_AUTO_INC on the destination table. */
 
3896
 
 
3897
      if (!lock_is_table_exclusive(prebuilt->table,
 
3898
              prebuilt->trx)) {
 
3899
        goto no_commit;
 
3900
      }
 
3901
 
 
3902
      /* Commit the transaction.  This will release the table
 
3903
      locks, so they have to be acquired again. */
 
3904
      getTransactionalEngine()->commit(user_session, 1);
 
3905
      /* Re-acquire the table lock on the source table. */
 
3906
      row_lock_table_for_mysql(prebuilt, src_table, mode);
 
3907
      /* We will need an IX lock on the destination table. */
 
3908
      prebuilt->sql_stat_start = TRUE;
 
3909
    }
 
3910
  }
 
3911
 
 
3912
  num_write_row++;
 
3913
 
 
3914
  /* This is the case where the table has an auto-increment column */
 
3915
  if (table->next_number_field && record == table->record[0]) {
 
3916
 
 
3917
    /* Reset the error code before calling
 
3918
    innobase_get_auto_increment(). */
 
3919
    prebuilt->autoinc_error = DB_SUCCESS;
 
3920
 
 
3921
    if ((error = update_auto_increment())) {
 
3922
 
 
3923
      /* We don't want to mask autoinc overflow errors. */
 
3924
      if (prebuilt->autoinc_error != DB_SUCCESS) {
 
3925
        error = (int) prebuilt->autoinc_error;
 
3926
 
 
3927
        goto report_error;
 
3928
      }
 
3929
 
 
3930
      /* MySQL errors are passed straight back. */
 
3931
      error_result = (int) error;
 
3932
      goto func_exit;
 
3933
    }
 
3934
 
 
3935
    auto_inc_used = TRUE;
 
3936
  }
 
3937
 
 
3938
  if (prebuilt->mysql_template == NULL
 
3939
      || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
 
3940
 
 
3941
    /* Build the template used in converting quickly between
 
3942
    the two database formats */
 
3943
 
 
3944
    build_template(prebuilt, NULL, table,
 
3945
             ROW_MYSQL_WHOLE_ROW);
 
3946
  }
 
3947
 
 
3948
  innodb_srv_conc_enter_innodb(prebuilt->trx);
 
3949
 
 
3950
  error = row_insert_for_mysql((byte*) record, prebuilt);
 
3951
 
 
3952
  /* Handle duplicate key errors */
 
3953
  if (auto_inc_used) {
 
3954
    ulint   err;
 
3955
    uint64_t  auto_inc;
 
3956
    uint64_t  col_max_value;
 
3957
 
 
3958
    /* Note the number of rows processed for this statement, used
 
3959
    by get_auto_increment() to determine the number of AUTO-INC
 
3960
    values to reserve. This is only useful for a mult-value INSERT
 
3961
    and is a statement level counter.*/
 
3962
    if (trx->n_autoinc_rows > 0) {
 
3963
      --trx->n_autoinc_rows;
 
3964
    }
 
3965
 
 
3966
    /* We need the upper limit of the col type to check for
 
3967
    whether we update the table autoinc counter or not. */
 
3968
    col_max_value = innobase_get_int_col_max_value(
 
3969
      table->next_number_field);
 
3970
 
 
3971
    /* Get the value that MySQL attempted to store in the table.*/
 
3972
    auto_inc = table->next_number_field->val_int();
 
3973
 
 
3974
    switch (error) {
 
3975
    case DB_DUPLICATE_KEY:
 
3976
 
 
3977
      /* A REPLACE command and LOAD DATA INFILE REPLACE
 
3978
      handle a duplicate key error themselves, but we
 
3979
      must update the autoinc counter if we are performing
 
3980
      those statements. */
 
3981
 
 
3982
      switch (sql_command) {
 
3983
      case SQLCOM_LOAD:
 
3984
        if ((trx->duplicates
 
3985
            & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
 
3986
 
 
3987
          goto set_max_autoinc;
 
3988
        }
 
3989
        break;
 
3990
 
 
3991
      case SQLCOM_REPLACE:
 
3992
      case SQLCOM_INSERT_SELECT:
 
3993
      case SQLCOM_REPLACE_SELECT:
 
3994
        goto set_max_autoinc;
 
3995
 
 
3996
      default:
 
3997
        break;
 
3998
      }
 
3999
 
 
4000
      break;
 
4001
 
 
4002
    case DB_SUCCESS:
 
4003
      /* If the actual value inserted is greater than
 
4004
      the upper limit of the interval, then we try and
 
4005
      update the table upper limit. Note: last_value
 
4006
      will be 0 if get_auto_increment() was not called.*/
 
4007
 
 
4008
      if (auto_inc <= col_max_value
 
4009
          && auto_inc >= prebuilt->autoinc_last_value) {
4010
4010
set_max_autoinc:
4011
 
                                ut_a(prebuilt->autoinc_increment > 0);
4012
 
 
4013
 
                                uint64_t        need;
4014
 
                                uint64_t        offset;
4015
 
 
4016
 
                                offset = prebuilt->autoinc_offset;
4017
 
                                need = prebuilt->autoinc_increment;
4018
 
 
4019
 
                                auto_inc = innobase_next_autoinc(
4020
 
                                        auto_inc, need, offset, col_max_value);
4021
 
 
4022
 
                                err = innobase_set_max_autoinc(auto_inc);
4023
 
 
4024
 
                                if (err != DB_SUCCESS) {
4025
 
                                        error = err;
4026
 
                                }
4027
 
                        }
4028
 
                        break;
4029
 
                }
4030
 
        }
4031
 
 
4032
 
        innodb_srv_conc_exit_innodb(prebuilt->trx);
 
4011
        ut_a(prebuilt->autoinc_increment > 0);
 
4012
 
 
4013
        uint64_t  need;
 
4014
        uint64_t  offset;
 
4015
 
 
4016
        offset = prebuilt->autoinc_offset;
 
4017
        need = prebuilt->autoinc_increment;
 
4018
 
 
4019
        auto_inc = innobase_next_autoinc(
 
4020
          auto_inc, need, offset, col_max_value);
 
4021
 
 
4022
        err = innobase_set_max_autoinc(auto_inc);
 
4023
 
 
4024
        if (err != DB_SUCCESS) {
 
4025
          error = err;
 
4026
        }
 
4027
      }
 
4028
      break;
 
4029
    }
 
4030
  }
 
4031
 
 
4032
  innodb_srv_conc_exit_innodb(prebuilt->trx);
4033
4033
 
4034
4034
report_error:
4035
 
        error_result = convert_error_code_to_mysql((int) error,
4036
 
                                                   prebuilt->table->flags,
4037
 
                                                   user_session);
 
4035
  error_result = convert_error_code_to_mysql((int) error,
 
4036
               prebuilt->table->flags,
 
4037
               user_session);
4038
4038
 
4039
4039
func_exit:
4040
 
        innobase_active_small();
 
4040
  innobase_active_small();
4041
4041
 
4042
 
        return(error_result);
 
4042
  return(error_result);
4043
4043
}
4044
4044
 
4045
4045
/**********************************************************************//**
4046
4046
Checks which fields have changed in a row and stores information
4047
4047
of them to an update vector.
4048
 
@return error number or 0 */
 
4048
@return error number or 0 */
4049
4049
static
4050
4050
int
4051
4051
calc_row_difference(
4052
4052
/*================*/
4053
 
        upd_t*          uvect,          /*!< in/out: update vector */
4054
 
        unsigned char*          old_row,        /*!< in: old row in MySQL format */
4055
 
        unsigned char*          new_row,        /*!< in: new row in MySQL format */
4056
 
        Table* table,           /*!< in: table in MySQL data
4057
 
                                        dictionary */
4058
 
        unsigned char*  upd_buff,       /*!< in: buffer to use */
4059
 
        ulint           buff_len,       /*!< in: buffer length */
4060
 
        row_prebuilt_t* prebuilt,       /*!< in: InnoDB prebuilt struct */
4061
 
        Session*        )               /*!< in: user thread */
 
4053
  upd_t*    uvect,    /*!< in/out: update vector */
 
4054
  unsigned char*    old_row,  /*!< in: old row in MySQL format */
 
4055
  unsigned char*    new_row,  /*!< in: new row in MySQL format */
 
4056
  Table* table,   /*!< in: table in MySQL data
 
4057
          dictionary */
 
4058
  unsigned char*  upd_buff, /*!< in: buffer to use */
 
4059
  ulint   buff_len, /*!< in: buffer length */
 
4060
  row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
 
4061
  Session*  )   /*!< in: user thread */
4062
4062
{
4063
 
        unsigned char*          original_upd_buff = upd_buff;
4064
 
        Field*          field;
4065
 
        enum_field_types field_mysql_type;
4066
 
        uint            n_fields;
4067
 
        ulint           o_len;
4068
 
        ulint           n_len;
4069
 
        ulint           col_pack_len;
4070
 
        const byte*     new_mysql_row_col;
4071
 
        const byte*     o_ptr;
4072
 
        const byte*     n_ptr;
4073
 
        byte*           buf;
4074
 
        upd_field_t*    ufield;
4075
 
        ulint           col_type;
4076
 
        ulint           n_changed = 0;
4077
 
        dfield_t        dfield;
4078
 
        dict_index_t*   clust_index;
4079
 
        uint            i= 0;
4080
 
 
4081
 
        n_fields = table->s->fields;
4082
 
        clust_index = dict_table_get_first_index(prebuilt->table);
4083
 
 
4084
 
        /* We use upd_buff to convert changed fields */
4085
 
        buf = (byte*) upd_buff;
4086
 
 
4087
 
        for (i = 0; i < n_fields; i++) {
4088
 
                field = table->field[i];
4089
 
 
4090
 
                o_ptr = (const byte*) old_row + get_field_offset(table, field);
4091
 
                n_ptr = (const byte*) new_row + get_field_offset(table, field);
4092
 
 
4093
 
                /* Use new_mysql_row_col and col_pack_len save the values */
4094
 
 
4095
 
                new_mysql_row_col = n_ptr;
4096
 
                col_pack_len = field->pack_length();
4097
 
 
4098
 
                o_len = col_pack_len;
4099
 
                n_len = col_pack_len;
4100
 
 
4101
 
                /* We use o_ptr and n_ptr to dig up the actual data for
4102
 
                comparison. */
4103
 
 
4104
 
                field_mysql_type = field->type();
4105
 
 
4106
 
                col_type = prebuilt->table->cols[i].mtype;
4107
 
 
4108
 
                switch (col_type) {
4109
 
 
4110
 
                case DATA_BLOB:
4111
 
                        o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
4112
 
                        n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
4113
 
 
4114
 
                        break;
4115
 
 
4116
 
                case DATA_VARCHAR:
4117
 
                case DATA_BINARY:
4118
 
                case DATA_VARMYSQL:
4119
 
                        if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
4120
 
                                /* This is a >= 5.0.3 type true VARCHAR where
4121
 
                                the real payload data length is stored in
4122
 
                                1 or 2 bytes */
4123
 
 
4124
 
                                o_ptr = row_mysql_read_true_varchar(
4125
 
                                        &o_len, o_ptr,
4126
 
                                        (ulint)
4127
 
                                        (((Field_varstring*)field)->length_bytes));
4128
 
 
4129
 
                                n_ptr = row_mysql_read_true_varchar(
4130
 
                                        &n_len, n_ptr,
4131
 
                                        (ulint)
4132
 
                                        (((Field_varstring*)field)->length_bytes));
4133
 
                        }
4134
 
 
4135
 
                        break;
4136
 
                default:
4137
 
                        ;
4138
 
                }
4139
 
 
4140
 
                if (field->null_ptr) {
4141
 
                        if (field_in_record_is_null(table, field,
4142
 
                                                        (char*) old_row)) {
4143
 
                                o_len = UNIV_SQL_NULL;
4144
 
                        }
4145
 
 
4146
 
                        if (field_in_record_is_null(table, field,
4147
 
                                                        (char*) new_row)) {
4148
 
                                n_len = UNIV_SQL_NULL;
4149
 
                        }
4150
 
                }
4151
 
 
4152
 
                if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
4153
 
                                        0 != memcmp(o_ptr, n_ptr, o_len))) {
4154
 
                        /* The field has changed */
4155
 
 
4156
 
                        ufield = uvect->fields + n_changed;
4157
 
 
4158
 
                        /* Let us use a dummy dfield to make the conversion
4159
 
                        from the MySQL column format to the InnoDB format */
4160
 
 
4161
 
                        dict_col_copy_type(prebuilt->table->cols + i,
4162
 
                                                     &dfield.type);
4163
 
 
4164
 
                        if (n_len != UNIV_SQL_NULL) {
4165
 
                                buf = row_mysql_store_col_in_innobase_format(
4166
 
                                        &dfield,
4167
 
                                        (byte*)buf,
4168
 
                                        TRUE,
4169
 
                                        new_mysql_row_col,
4170
 
                                        col_pack_len,
4171
 
                                        dict_table_is_comp(prebuilt->table));
4172
 
                                dfield_copy_data(&ufield->new_val, &dfield);
4173
 
                        } else {
4174
 
                                dfield_set_null(&ufield->new_val);
4175
 
                        }
4176
 
 
4177
 
                        ufield->exp = NULL;
4178
 
                        ufield->orig_len = 0;
4179
 
                        ufield->field_no = dict_col_get_clust_pos(
4180
 
                                &prebuilt->table->cols[i], clust_index);
4181
 
                        n_changed++;
4182
 
                }
4183
 
        }
4184
 
 
4185
 
        uvect->n_fields = n_changed;
4186
 
        uvect->info_bits = 0;
4187
 
 
4188
 
        ut_a(buf <= (byte*)original_upd_buff + buff_len);
4189
 
 
4190
 
        return(0);
 
4063
  unsigned char*    original_upd_buff = upd_buff;
 
4064
  Field*    field;
 
4065
  enum_field_types field_mysql_type;
 
4066
  uint    n_fields;
 
4067
  ulint   o_len;
 
4068
  ulint   n_len;
 
4069
  ulint   col_pack_len;
 
4070
  const byte* new_mysql_row_col;
 
4071
  const byte* o_ptr;
 
4072
  const byte* n_ptr;
 
4073
  byte*   buf;
 
4074
  upd_field_t*  ufield;
 
4075
  ulint   col_type;
 
4076
  ulint   n_changed = 0;
 
4077
  dfield_t  dfield;
 
4078
  dict_index_t* clust_index;
 
4079
  uint    i= 0;
 
4080
 
 
4081
  n_fields = table->s->fields;
 
4082
  clust_index = dict_table_get_first_index(prebuilt->table);
 
4083
 
 
4084
  /* We use upd_buff to convert changed fields */
 
4085
  buf = (byte*) upd_buff;
 
4086
 
 
4087
  for (i = 0; i < n_fields; i++) {
 
4088
    field = table->field[i];
 
4089
 
 
4090
    o_ptr = (const byte*) old_row + get_field_offset(table, field);
 
4091
    n_ptr = (const byte*) new_row + get_field_offset(table, field);
 
4092
 
 
4093
    /* Use new_mysql_row_col and col_pack_len save the values */
 
4094
 
 
4095
    new_mysql_row_col = n_ptr;
 
4096
    col_pack_len = field->pack_length();
 
4097
 
 
4098
    o_len = col_pack_len;
 
4099
    n_len = col_pack_len;
 
4100
 
 
4101
    /* We use o_ptr and n_ptr to dig up the actual data for
 
4102
    comparison. */
 
4103
 
 
4104
    field_mysql_type = field->type();
 
4105
 
 
4106
    col_type = prebuilt->table->cols[i].mtype;
 
4107
 
 
4108
    switch (col_type) {
 
4109
 
 
4110
    case DATA_BLOB:
 
4111
      o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
 
4112
      n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
 
4113
 
 
4114
      break;
 
4115
 
 
4116
    case DATA_VARCHAR:
 
4117
    case DATA_BINARY:
 
4118
    case DATA_VARMYSQL:
 
4119
      if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
 
4120
        /* This is a >= 5.0.3 type true VARCHAR where
 
4121
        the real payload data length is stored in
 
4122
        1 or 2 bytes */
 
4123
 
 
4124
        o_ptr = row_mysql_read_true_varchar(
 
4125
          &o_len, o_ptr,
 
4126
          (ulint)
 
4127
          (((Field_varstring*)field)->length_bytes));
 
4128
 
 
4129
        n_ptr = row_mysql_read_true_varchar(
 
4130
          &n_len, n_ptr,
 
4131
          (ulint)
 
4132
          (((Field_varstring*)field)->length_bytes));
 
4133
      }
 
4134
 
 
4135
      break;
 
4136
    default:
 
4137
      ;
 
4138
    }
 
4139
 
 
4140
    if (field->null_ptr) {
 
4141
      if (field_in_record_is_null(table, field,
 
4142
              (char*) old_row)) {
 
4143
        o_len = UNIV_SQL_NULL;
 
4144
      }
 
4145
 
 
4146
      if (field_in_record_is_null(table, field,
 
4147
              (char*) new_row)) {
 
4148
        n_len = UNIV_SQL_NULL;
 
4149
      }
 
4150
    }
 
4151
 
 
4152
    if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
 
4153
          0 != memcmp(o_ptr, n_ptr, o_len))) {
 
4154
      /* The field has changed */
 
4155
 
 
4156
      ufield = uvect->fields + n_changed;
 
4157
 
 
4158
      /* Let us use a dummy dfield to make the conversion
 
4159
      from the MySQL column format to the InnoDB format */
 
4160
 
 
4161
      dict_col_copy_type(prebuilt->table->cols + i,
 
4162
                 &dfield.type);
 
4163
 
 
4164
      if (n_len != UNIV_SQL_NULL) {
 
4165
        buf = row_mysql_store_col_in_innobase_format(
 
4166
          &dfield,
 
4167
          (byte*)buf,
 
4168
          TRUE,
 
4169
          new_mysql_row_col,
 
4170
          col_pack_len,
 
4171
          dict_table_is_comp(prebuilt->table));
 
4172
        dfield_copy_data(&ufield->new_val, &dfield);
 
4173
      } else {
 
4174
        dfield_set_null(&ufield->new_val);
 
4175
      }
 
4176
 
 
4177
      ufield->exp = NULL;
 
4178
      ufield->orig_len = 0;
 
4179
      ufield->field_no = dict_col_get_clust_pos(
 
4180
        &prebuilt->table->cols[i], clust_index);
 
4181
      n_changed++;
 
4182
    }
 
4183
  }
 
4184
 
 
4185
  uvect->n_fields = n_changed;
 
4186
  uvect->info_bits = 0;
 
4187
 
 
4188
  ut_a(buf <= (byte*)original_upd_buff + buff_len);
 
4189
 
 
4190
  return(0);
4191
4191
}
4192
4192
 
4193
4193
/**********************************************************************//**
4197
4197
TODO: currently InnoDB does not prevent the 'Halloween problem':
4198
4198
in a searched update a single row can get updated several times
4199
4199
if its index columns are updated!
4200
 
@return error number or 0 */
 
4200
@return error number or 0 */
4201
4201
UNIV_INTERN
4202
4202
int
4203
4203
ha_innobase::update_row(
4204
4204
/*====================*/
4205
 
        const unsigned char*    old_row,/*!< in: old row in MySQL format */
4206
 
        unsigned char*          new_row)/*!< in: new row in MySQL format */
 
4205
  const unsigned char*  old_row,/*!< in: old row in MySQL format */
 
4206
  unsigned char*    new_row)/*!< in: new row in MySQL format */
4207
4207
{
4208
 
        upd_t*          uvect;
4209
 
        int             error = 0;
4210
 
        trx_t*          trx = session_to_trx(user_session);
4211
 
 
4212
 
        ut_a(prebuilt->trx == trx);
4213
 
 
4214
 
        ha_statistic_increment(&system_status_var::ha_update_count);
4215
 
 
4216
 
        if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
4217
 
                table->timestamp_field->set_time();
4218
 
 
4219
 
        if (prebuilt->upd_node) {
4220
 
                uvect = prebuilt->upd_node->update;
4221
 
        } else {
4222
 
                uvect = row_get_prebuilt_update_vector(prebuilt);
4223
 
        }
4224
 
 
4225
 
        /* Build an update vector from the modified fields in the rows
4226
 
        (uses upd_buff of the handle) */
4227
 
 
4228
 
        calc_row_difference(uvect, (unsigned char*) old_row, new_row, table,
4229
 
                        upd_buff, (ulint)upd_and_key_val_buff_len,
4230
 
                        prebuilt, user_session);
4231
 
 
4232
 
        /* This is not a delete */
4233
 
        prebuilt->upd_node->is_delete = FALSE;
4234
 
 
4235
 
        ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
4236
 
 
4237
 
        innodb_srv_conc_enter_innodb(trx);
4238
 
 
4239
 
        error = row_update_for_mysql((byte*) old_row, prebuilt);
4240
 
 
4241
 
        /* We need to do some special AUTOINC handling for the following case:
4242
 
 
4243
 
        INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
4244
 
 
4245
 
        We need to use the AUTOINC counter that was actually used by
4246
 
        MySQL in the UPDATE statement, which can be different from the
4247
 
        value used in the INSERT statement.*/
4248
 
 
4249
 
        if (error == DB_SUCCESS
4250
 
            && table->next_number_field
4251
 
            && new_row == table->record[0]
4252
 
            && session_sql_command(user_session) == SQLCOM_INSERT
4253
 
            && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
4254
 
                == TRX_DUP_IGNORE)  {
4255
 
 
4256
 
                uint64_t        auto_inc;
4257
 
                uint64_t        col_max_value;
4258
 
 
4259
 
                auto_inc = table->next_number_field->val_int();
4260
 
 
4261
 
                /* We need the upper limit of the col type to check for
4262
 
                whether we update the table autoinc counter or not. */
4263
 
                col_max_value = innobase_get_int_col_max_value(
4264
 
                        table->next_number_field);
4265
 
 
4266
 
                if (auto_inc <= col_max_value && auto_inc != 0) {
4267
 
 
4268
 
                        uint64_t        need;
4269
 
                        uint64_t        offset;
4270
 
 
4271
 
                        offset = prebuilt->autoinc_offset;
4272
 
                        need = prebuilt->autoinc_increment;
4273
 
 
4274
 
                        auto_inc = innobase_next_autoinc(
4275
 
                                auto_inc, need, offset, col_max_value);
4276
 
 
4277
 
                        error = innobase_set_max_autoinc(auto_inc);
4278
 
                }
4279
 
        }
4280
 
 
4281
 
        innodb_srv_conc_exit_innodb(trx);
4282
 
 
4283
 
        error = convert_error_code_to_mysql(error,
4284
 
                                            prebuilt->table->flags,
 
4208
  upd_t*    uvect;
 
4209
  int   error = 0;
 
4210
  trx_t*    trx = session_to_trx(user_session);
 
4211
 
 
4212
  ut_a(prebuilt->trx == trx);
 
4213
 
 
4214
  ha_statistic_increment(&system_status_var::ha_update_count);
 
4215
 
 
4216
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
 
4217
    table->timestamp_field->set_time();
 
4218
 
 
4219
  if (prebuilt->upd_node) {
 
4220
    uvect = prebuilt->upd_node->update;
 
4221
  } else {
 
4222
    uvect = row_get_prebuilt_update_vector(prebuilt);
 
4223
  }
 
4224
 
 
4225
  /* Build an update vector from the modified fields in the rows
 
4226
  (uses upd_buff of the handle) */
 
4227
 
 
4228
  calc_row_difference(uvect, (unsigned char*) old_row, new_row, table,
 
4229
      upd_buff, (ulint)upd_and_key_val_buff_len,
 
4230
      prebuilt, user_session);
 
4231
 
 
4232
  /* This is not a delete */
 
4233
  prebuilt->upd_node->is_delete = FALSE;
 
4234
 
 
4235
  ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
 
4236
 
 
4237
  innodb_srv_conc_enter_innodb(trx);
 
4238
 
 
4239
  error = row_update_for_mysql((byte*) old_row, prebuilt);
 
4240
 
 
4241
  /* We need to do some special AUTOINC handling for the following case:
 
4242
 
 
4243
  INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
 
4244
 
 
4245
  We need to use the AUTOINC counter that was actually used by
 
4246
  MySQL in the UPDATE statement, which can be different from the
 
4247
  value used in the INSERT statement.*/
 
4248
 
 
4249
  if (error == DB_SUCCESS
 
4250
      && table->next_number_field
 
4251
      && new_row == table->record[0]
 
4252
      && session_sql_command(user_session) == SQLCOM_INSERT
 
4253
      && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
 
4254
    == TRX_DUP_IGNORE)  {
 
4255
 
 
4256
    uint64_t  auto_inc;
 
4257
    uint64_t  col_max_value;
 
4258
 
 
4259
    auto_inc = table->next_number_field->val_int();
 
4260
 
 
4261
    /* We need the upper limit of the col type to check for
 
4262
    whether we update the table autoinc counter or not. */
 
4263
    col_max_value = innobase_get_int_col_max_value(
 
4264
      table->next_number_field);
 
4265
 
 
4266
    if (auto_inc <= col_max_value && auto_inc != 0) {
 
4267
 
 
4268
      uint64_t  need;
 
4269
      uint64_t  offset;
 
4270
 
 
4271
      offset = prebuilt->autoinc_offset;
 
4272
      need = prebuilt->autoinc_increment;
 
4273
 
 
4274
      auto_inc = innobase_next_autoinc(
 
4275
        auto_inc, need, offset, col_max_value);
 
4276
 
 
4277
      error = innobase_set_max_autoinc(auto_inc);
 
4278
    }
 
4279
  }
 
4280
 
 
4281
  innodb_srv_conc_exit_innodb(trx);
 
4282
 
 
4283
  error = convert_error_code_to_mysql(error,
 
4284
              prebuilt->table->flags,
4285
4285
                                            user_session);
4286
4286
 
4287
 
        if (error == 0 /* success */
4288
 
            && uvect->n_fields == 0 /* no columns were updated */) {
4289
 
 
4290
 
                /* This is the same as success, but instructs
4291
 
                MySQL that the row is not really updated and it
4292
 
                should not increase the count of updated rows.
4293
 
                This is fix for http://bugs.mysql.com/29157 */
4294
 
                error = HA_ERR_RECORD_IS_THE_SAME;
4295
 
        }
4296
 
 
4297
 
        /* Tell InnoDB server that there might be work for
4298
 
        utility threads: */
4299
 
 
4300
 
        innobase_active_small();
4301
 
 
4302
 
        return(error);
 
4287
  if (error == 0 /* success */
 
4288
      && uvect->n_fields == 0 /* no columns were updated */) {
 
4289
 
 
4290
    /* This is the same as success, but instructs
 
4291
    MySQL that the row is not really updated and it
 
4292
    should not increase the count of updated rows.
 
4293
    This is fix for http://bugs.mysql.com/29157 */
 
4294
    error = HA_ERR_RECORD_IS_THE_SAME;
 
4295
  }
 
4296
 
 
4297
  /* Tell InnoDB server that there might be work for
 
4298
  utility threads: */
 
4299
 
 
4300
  innobase_active_small();
 
4301
 
 
4302
  return(error);
4303
4303
}
4304
4304
 
4305
4305
/**********************************************************************//**
4306
4306
Deletes a row given as the parameter.
4307
 
@return error number or 0 */
 
4307
@return error number or 0 */
4308
4308
UNIV_INTERN
4309
4309
int
4310
4310
ha_innobase::delete_row(
4311
4311
/*====================*/
4312
 
        const unsigned char*    record) /*!< in: a row in MySQL format */
 
4312
  const unsigned char*  record) /*!< in: a row in MySQL format */
4313
4313
{
4314
 
        int             error = 0;
4315
 
        trx_t*          trx = session_to_trx(user_session);
4316
 
 
4317
 
        ut_a(prebuilt->trx == trx);
4318
 
 
4319
 
        ha_statistic_increment(&system_status_var::ha_delete_count);
4320
 
 
4321
 
        if (!prebuilt->upd_node) {
4322
 
                row_get_prebuilt_update_vector(prebuilt);
4323
 
        }
4324
 
 
4325
 
        /* This is a delete */
4326
 
 
4327
 
        prebuilt->upd_node->is_delete = TRUE;
4328
 
 
4329
 
        innodb_srv_conc_enter_innodb(trx);
4330
 
 
4331
 
        error = row_update_for_mysql((byte*) record, prebuilt);
4332
 
 
4333
 
        innodb_srv_conc_exit_innodb(trx);
4334
 
 
4335
 
        error = convert_error_code_to_mysql(
4336
 
                error, prebuilt->table->flags, user_session);
4337
 
 
4338
 
        /* Tell the InnoDB server that there might be work for
4339
 
        utility threads: */
4340
 
 
4341
 
        innobase_active_small();
4342
 
 
4343
 
        return(error);
 
4314
  int   error = 0;
 
4315
  trx_t*    trx = session_to_trx(user_session);
 
4316
 
 
4317
  ut_a(prebuilt->trx == trx);
 
4318
 
 
4319
  ha_statistic_increment(&system_status_var::ha_delete_count);
 
4320
 
 
4321
  if (!prebuilt->upd_node) {
 
4322
    row_get_prebuilt_update_vector(prebuilt);
 
4323
  }
 
4324
 
 
4325
  /* This is a delete */
 
4326
 
 
4327
  prebuilt->upd_node->is_delete = TRUE;
 
4328
 
 
4329
  innodb_srv_conc_enter_innodb(trx);
 
4330
 
 
4331
  error = row_update_for_mysql((byte*) record, prebuilt);
 
4332
 
 
4333
  innodb_srv_conc_exit_innodb(trx);
 
4334
 
 
4335
  error = convert_error_code_to_mysql(
 
4336
    error, prebuilt->table->flags, user_session);
 
4337
 
 
4338
  /* Tell the InnoDB server that there might be work for
 
4339
  utility threads: */
 
4340
 
 
4341
  innobase_active_small();
 
4342
 
 
4343
  return(error);
4344
4344
}
4345
4345
 
4346
4346
/**********************************************************************//**
4352
4352
ha_innobase::unlock_row(void)
4353
4353
/*=========================*/
4354
4354
{
4355
 
        /* Consistent read does not take any locks, thus there is
4356
 
        nothing to unlock. */
4357
 
 
4358
 
        if (prebuilt->select_lock_type == LOCK_NONE) {
4359
 
          return;
4360
 
        }
4361
 
 
4362
 
        switch (prebuilt->row_read_type) {
4363
 
        case ROW_READ_WITH_LOCKS:
4364
 
                if (!srv_locks_unsafe_for_binlog
4365
 
                    && prebuilt->trx->isolation_level
4366
 
                    != TRX_ISO_READ_COMMITTED) {
4367
 
                        break;
4368
 
                }
4369
 
                /* fall through */
4370
 
        case ROW_READ_TRY_SEMI_CONSISTENT:
4371
 
                row_unlock_for_mysql(prebuilt, FALSE);
4372
 
                break;
4373
 
        case ROW_READ_DID_SEMI_CONSISTENT:
4374
 
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4375
 
                break;
4376
 
        }
4377
 
 
4378
 
        return;
 
4355
  /* Consistent read does not take any locks, thus there is
 
4356
  nothing to unlock. */
 
4357
 
 
4358
  if (prebuilt->select_lock_type == LOCK_NONE) {
 
4359
    return;
 
4360
  }
 
4361
 
 
4362
  switch (prebuilt->row_read_type) {
 
4363
  case ROW_READ_WITH_LOCKS:
 
4364
    if (!srv_locks_unsafe_for_binlog
 
4365
        && prebuilt->trx->isolation_level
 
4366
        != TRX_ISO_READ_COMMITTED) {
 
4367
      break;
 
4368
    }
 
4369
    /* fall through */
 
4370
  case ROW_READ_TRY_SEMI_CONSISTENT:
 
4371
    row_unlock_for_mysql(prebuilt, FALSE);
 
4372
    break;
 
4373
  case ROW_READ_DID_SEMI_CONSISTENT:
 
4374
    prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4375
    break;
 
4376
  }
 
4377
 
 
4378
  return;
4379
4379
}
4380
4380
 
4381
4381
/* See Cursor.h and row0mysql.h for docs on this function. */
4384
4384
ha_innobase::was_semi_consistent_read(void)
4385
4385
/*=======================================*/
4386
4386
{
4387
 
        return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
 
4387
  return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
4388
4388
}
4389
4389
 
4390
4390
/* See Cursor.h and row0mysql.h for docs on this function. */
4393
4393
ha_innobase::try_semi_consistent_read(bool yes)
4394
4394
/*===========================================*/
4395
4395
{
4396
 
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
4397
 
 
4398
 
        /* Row read type is set to semi consistent read if this was
4399
 
        requested by the MySQL and either innodb_locks_unsafe_for_binlog
4400
 
        option is used or this session is using READ COMMITTED isolation
4401
 
        level. */
4402
 
 
4403
 
        if (yes
4404
 
            && (srv_locks_unsafe_for_binlog
4405
 
                || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
4406
 
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
4407
 
        } else {
4408
 
                prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
4409
 
        }
 
4396
  ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
4397
 
 
4398
  /* Row read type is set to semi consistent read if this was
 
4399
  requested by the MySQL and either innodb_locks_unsafe_for_binlog
 
4400
  option is used or this session is using READ COMMITTED isolation
 
4401
  level. */
 
4402
 
 
4403
  if (yes
 
4404
      && (srv_locks_unsafe_for_binlog
 
4405
    || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
 
4406
    prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4407
  } else {
 
4408
    prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
 
4409
  }
4410
4410
}
4411
4411
 
4412
4412
/******************************************************************//**
4413
4413
Initializes a handle to use an index.
4414
 
@return 0 or error number */
 
4414
@return 0 or error number */
4415
4415
UNIV_INTERN
4416
4416
int
4417
4417
ha_innobase::index_init(
4418
4418
/*====================*/
4419
 
        uint    keynr,  /*!< in: key (index) number */
4420
 
        bool )          /*!< in: 1 if result MUST be sorted according to index */
 
4419
  uint  keynr,  /*!< in: key (index) number */
 
4420
  bool )    /*!< in: 1 if result MUST be sorted according to index */
4421
4421
{
4422
 
        return(change_active_index(keynr));
 
4422
  return(change_active_index(keynr));
4423
4423
}
4424
4424
 
4425
4425
/******************************************************************//**
4426
4426
Currently does nothing.
4427
 
@return 0 */
 
4427
@return 0 */
4428
4428
UNIV_INTERN
4429
4429
int
4430
4430
ha_innobase::index_end(void)
4431
4431
/*========================*/
4432
4432
{
4433
 
        int     error   = 0;
4434
 
        active_index=MAX_KEY;
4435
 
        return(error);
 
4433
  int error = 0;
 
4434
  active_index=MAX_KEY;
 
4435
  return(error);
4436
4436
}
4437
4437
 
4438
4438
/*********************************************************************//**
4442
4442
ulint
4443
4443
convert_search_mode_to_innobase(
4444
4444
/*============================*/
4445
 
        enum ha_rkey_function   find_flag)
 
4445
  enum ha_rkey_function find_flag)
4446
4446
{
4447
 
        switch (find_flag) {
4448
 
        case HA_READ_KEY_EXACT:
4449
 
                /* this does not require the index to be UNIQUE */
4450
 
                return(PAGE_CUR_GE);
4451
 
        case HA_READ_KEY_OR_NEXT:
4452
 
                return(PAGE_CUR_GE);
4453
 
        case HA_READ_KEY_OR_PREV:
4454
 
                return(PAGE_CUR_LE);
4455
 
        case HA_READ_AFTER_KEY: 
4456
 
                return(PAGE_CUR_G);
4457
 
        case HA_READ_BEFORE_KEY:
4458
 
                return(PAGE_CUR_L);
4459
 
        case HA_READ_PREFIX:
4460
 
                return(PAGE_CUR_GE);
4461
 
        case HA_READ_PREFIX_LAST:
4462
 
                return(PAGE_CUR_LE);
4463
 
        case HA_READ_PREFIX_LAST_OR_PREV:
4464
 
                return(PAGE_CUR_LE);
4465
 
                /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
4466
 
                pass a complete-field prefix of a key value as the search
4467
 
                tuple. I.e., it is not allowed that the last field would
4468
 
                just contain n first bytes of the full field value.
4469
 
                MySQL uses a 'padding' trick to convert LIKE 'abc%'
4470
 
                type queries so that it can use as a search tuple
4471
 
                a complete-field-prefix of a key value. Thus, the InnoDB
4472
 
                search mode PAGE_CUR_LE_OR_EXTENDS is never used.
4473
 
                TODO: when/if MySQL starts to use also partial-field
4474
 
                prefixes, we have to deal with stripping of spaces
4475
 
                and comparison of non-latin1 char type fields in
4476
 
                innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
4477
 
                work correctly. */
4478
 
        case HA_READ_MBR_CONTAIN:
4479
 
        case HA_READ_MBR_INTERSECT:
4480
 
        case HA_READ_MBR_WITHIN:
4481
 
        case HA_READ_MBR_DISJOINT:
4482
 
        case HA_READ_MBR_EQUAL:
4483
 
                return(PAGE_CUR_UNSUPP);
4484
 
        /* do not use "default:" in order to produce a gcc warning:
4485
 
        enumeration value '...' not handled in switch
4486
 
        (if -Wswitch or -Wall is used) */
4487
 
        }
4488
 
 
4489
 
        my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
4490
 
 
4491
 
        return(PAGE_CUR_UNSUPP);
 
4447
  switch (find_flag) {
 
4448
  case HA_READ_KEY_EXACT:
 
4449
    /* this does not require the index to be UNIQUE */
 
4450
    return(PAGE_CUR_GE);
 
4451
  case HA_READ_KEY_OR_NEXT:
 
4452
    return(PAGE_CUR_GE);
 
4453
  case HA_READ_KEY_OR_PREV:
 
4454
    return(PAGE_CUR_LE);
 
4455
  case HA_READ_AFTER_KEY: 
 
4456
    return(PAGE_CUR_G);
 
4457
  case HA_READ_BEFORE_KEY:
 
4458
    return(PAGE_CUR_L);
 
4459
  case HA_READ_PREFIX:
 
4460
    return(PAGE_CUR_GE);
 
4461
  case HA_READ_PREFIX_LAST:
 
4462
    return(PAGE_CUR_LE);
 
4463
  case HA_READ_PREFIX_LAST_OR_PREV:
 
4464
    return(PAGE_CUR_LE);
 
4465
    /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
 
4466
    pass a complete-field prefix of a key value as the search
 
4467
    tuple. I.e., it is not allowed that the last field would
 
4468
    just contain n first bytes of the full field value.
 
4469
    MySQL uses a 'padding' trick to convert LIKE 'abc%'
 
4470
    type queries so that it can use as a search tuple
 
4471
    a complete-field-prefix of a key value. Thus, the InnoDB
 
4472
    search mode PAGE_CUR_LE_OR_EXTENDS is never used.
 
4473
    TODO: when/if MySQL starts to use also partial-field
 
4474
    prefixes, we have to deal with stripping of spaces
 
4475
    and comparison of non-latin1 char type fields in
 
4476
    innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
 
4477
    work correctly. */
 
4478
  case HA_READ_MBR_CONTAIN:
 
4479
  case HA_READ_MBR_INTERSECT:
 
4480
  case HA_READ_MBR_WITHIN:
 
4481
  case HA_READ_MBR_DISJOINT:
 
4482
  case HA_READ_MBR_EQUAL:
 
4483
    return(PAGE_CUR_UNSUPP);
 
4484
  /* do not use "default:" in order to produce a gcc warning:
 
4485
  enumeration value '...' not handled in switch
 
4486
  (if -Wswitch or -Wall is used) */
 
4487
  }
 
4488
 
 
4489
  my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
 
4490
 
 
4491
  return(PAGE_CUR_UNSUPP);
4492
4492
}
4493
4493
 
4494
4494
/*
4552
4552
/**********************************************************************//**
4553
4553
Positions an index cursor to the index specified in the handle. Fetches the
4554
4554
row if any.
4555
 
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
 
4555
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
4556
4556
UNIV_INTERN
4557
4557
int
4558
4558
ha_innobase::index_read(
4559
4559
/*====================*/
4560
 
        unsigned char*          buf,    /*!< in/out: buffer for the returned
4561
 
                                        row */
4562
 
        const unsigned char*    key_ptr,/*!< in: key value; if this is NULL
4563
 
                                        we position the cursor at the
4564
 
                                        start or end of index; this can
4565
 
                                        also contain an InnoDB row id, in
4566
 
                                        which case key_len is the InnoDB
4567
 
                                        row id length; the key value can
4568
 
                                        also be a prefix of a full key value,
4569
 
                                        and the last column can be a prefix
4570
 
                                        of a full column */
4571
 
        uint                    key_len,/*!< in: key value length */
4572
 
        enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
 
4560
  unsigned char*    buf,  /*!< in/out: buffer for the returned
 
4561
          row */
 
4562
  const unsigned char*  key_ptr,/*!< in: key value; if this is NULL
 
4563
          we position the cursor at the
 
4564
          start or end of index; this can
 
4565
          also contain an InnoDB row id, in
 
4566
          which case key_len is the InnoDB
 
4567
          row id length; the key value can
 
4568
          also be a prefix of a full key value,
 
4569
          and the last column can be a prefix
 
4570
          of a full column */
 
4571
  uint      key_len,/*!< in: key value length */
 
4572
  enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
4573
4573
{
4574
 
        ulint           mode;
4575
 
        dict_index_t*   index;
4576
 
        ulint           match_mode      = 0;
4577
 
        int             error;
4578
 
        ulint           ret;
4579
 
 
4580
 
        ut_a(prebuilt->trx == session_to_trx(user_session));
4581
 
 
4582
 
        ha_statistic_increment(&system_status_var::ha_read_key_count);
4583
 
 
4584
 
        index = prebuilt->index;
4585
 
 
4586
 
        /* Note that if the index for which the search template is built is not
4587
 
        necessarily prebuilt->index, but can also be the clustered index */
4588
 
 
4589
 
        if (prebuilt->sql_stat_start) {
4590
 
                build_template(prebuilt, user_session, table,
4591
 
                               ROW_MYSQL_REC_FIELDS);
4592
 
        }
4593
 
 
4594
 
        if (key_ptr) {
4595
 
                /* Convert the search key value to InnoDB format into
4596
 
                prebuilt->search_tuple */
4597
 
 
4598
 
                row_sel_convert_mysql_key_to_innobase(
4599
 
                        prebuilt->search_tuple,
4600
 
                        (byte*) key_val_buff,
4601
 
                        (ulint)upd_and_key_val_buff_len,
4602
 
                        index,
4603
 
                        (byte*) key_ptr,
4604
 
                        (ulint) key_len,
4605
 
                        prebuilt->trx);
4606
 
        } else {
4607
 
                /* We position the cursor to the last or the first entry
4608
 
                in the index */
4609
 
 
4610
 
                dtuple_set_n_fields(prebuilt->search_tuple, 0);
4611
 
        }
4612
 
 
4613
 
        mode = convert_search_mode_to_innobase(find_flag);
4614
 
 
4615
 
        match_mode = 0;
4616
 
 
4617
 
        if (find_flag == HA_READ_KEY_EXACT) {
4618
 
 
4619
 
                match_mode = ROW_SEL_EXACT;
4620
 
 
4621
 
        } else if (find_flag == HA_READ_PREFIX
4622
 
                   || find_flag == HA_READ_PREFIX_LAST) {
4623
 
 
4624
 
                match_mode = ROW_SEL_EXACT_PREFIX;
4625
 
        }
4626
 
 
4627
 
        last_match_mode = (uint) match_mode;
4628
 
 
4629
 
        if (mode != PAGE_CUR_UNSUPP) {
4630
 
 
4631
 
                innodb_srv_conc_enter_innodb(prebuilt->trx);
4632
 
 
4633
 
                ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
4634
 
                                           match_mode, 0);
4635
 
 
4636
 
                innodb_srv_conc_exit_innodb(prebuilt->trx);
4637
 
        } else {
4638
 
 
4639
 
                ret = DB_UNSUPPORTED;
4640
 
        }
4641
 
 
4642
 
        switch (ret) {
4643
 
        case DB_SUCCESS:
4644
 
                error = 0;
4645
 
                table->status = 0;
4646
 
                break;
4647
 
        case DB_RECORD_NOT_FOUND:
4648
 
                error = HA_ERR_KEY_NOT_FOUND;
4649
 
                table->status = STATUS_NOT_FOUND;
4650
 
                break;
4651
 
        case DB_END_OF_INDEX:
4652
 
                error = HA_ERR_KEY_NOT_FOUND;
4653
 
                table->status = STATUS_NOT_FOUND;
4654
 
                break;
4655
 
        default:
4656
 
                error = convert_error_code_to_mysql((int) ret,
4657
 
                                                    prebuilt->table->flags,
4658
 
                                                    user_session);
4659
 
                table->status = STATUS_NOT_FOUND;
4660
 
                break;
4661
 
        }
4662
 
 
4663
 
        return(error);
 
4574
  ulint   mode;
 
4575
  dict_index_t* index;
 
4576
  ulint   match_mode  = 0;
 
4577
  int   error;
 
4578
  ulint   ret;
 
4579
 
 
4580
  ut_a(prebuilt->trx == session_to_trx(user_session));
 
4581
 
 
4582
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
4583
 
 
4584
  index = prebuilt->index;
 
4585
 
 
4586
  /* Note that if the index for which the search template is built is not
 
4587
  necessarily prebuilt->index, but can also be the clustered index */
 
4588
 
 
4589
  if (prebuilt->sql_stat_start) {
 
4590
    build_template(prebuilt, user_session, table,
 
4591
             ROW_MYSQL_REC_FIELDS);
 
4592
  }
 
4593
 
 
4594
  if (key_ptr) {
 
4595
    /* Convert the search key value to InnoDB format into
 
4596
    prebuilt->search_tuple */
 
4597
 
 
4598
    row_sel_convert_mysql_key_to_innobase(
 
4599
      prebuilt->search_tuple,
 
4600
      (byte*) key_val_buff,
 
4601
      (ulint)upd_and_key_val_buff_len,
 
4602
      index,
 
4603
      (byte*) key_ptr,
 
4604
      (ulint) key_len,
 
4605
      prebuilt->trx);
 
4606
  } else {
 
4607
    /* We position the cursor to the last or the first entry
 
4608
    in the index */
 
4609
 
 
4610
    dtuple_set_n_fields(prebuilt->search_tuple, 0);
 
4611
  }
 
4612
 
 
4613
  mode = convert_search_mode_to_innobase(find_flag);
 
4614
 
 
4615
  match_mode = 0;
 
4616
 
 
4617
  if (find_flag == HA_READ_KEY_EXACT) {
 
4618
 
 
4619
    match_mode = ROW_SEL_EXACT;
 
4620
 
 
4621
  } else if (find_flag == HA_READ_PREFIX
 
4622
       || find_flag == HA_READ_PREFIX_LAST) {
 
4623
 
 
4624
    match_mode = ROW_SEL_EXACT_PREFIX;
 
4625
  }
 
4626
 
 
4627
  last_match_mode = (uint) match_mode;
 
4628
 
 
4629
  if (mode != PAGE_CUR_UNSUPP) {
 
4630
 
 
4631
    innodb_srv_conc_enter_innodb(prebuilt->trx);
 
4632
 
 
4633
    ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
 
4634
             match_mode, 0);
 
4635
 
 
4636
    innodb_srv_conc_exit_innodb(prebuilt->trx);
 
4637
  } else {
 
4638
 
 
4639
    ret = DB_UNSUPPORTED;
 
4640
  }
 
4641
 
 
4642
  switch (ret) {
 
4643
  case DB_SUCCESS:
 
4644
    error = 0;
 
4645
    table->status = 0;
 
4646
    break;
 
4647
  case DB_RECORD_NOT_FOUND:
 
4648
    error = HA_ERR_KEY_NOT_FOUND;
 
4649
    table->status = STATUS_NOT_FOUND;
 
4650
    break;
 
4651
  case DB_END_OF_INDEX:
 
4652
    error = HA_ERR_KEY_NOT_FOUND;
 
4653
    table->status = STATUS_NOT_FOUND;
 
4654
    break;
 
4655
  default:
 
4656
    error = convert_error_code_to_mysql((int) ret,
 
4657
                prebuilt->table->flags,
 
4658
                user_session);
 
4659
    table->status = STATUS_NOT_FOUND;
 
4660
    break;
 
4661
  }
 
4662
 
 
4663
  return(error);
4664
4664
}
4665
4665
 
4666
4666
/*******************************************************************//**
4667
4667
The following functions works like index_read, but it find the last
4668
4668
row with the current key value or prefix.
4669
 
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
 
4669
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
4670
4670
UNIV_INTERN
4671
4671
int
4672
4672
ha_innobase::index_read_last(
4673
4673
/*=========================*/
4674
 
        unsigned char*  buf,    /*!< out: fetched row */
4675
 
        const unsigned char*    key_ptr,/*!< in: key value, or a prefix of a full
4676
 
                                key value */
4677
 
        uint            key_len)/*!< in: length of the key val or prefix
4678
 
                                in bytes */
 
4674
  unsigned char*  buf,  /*!< out: fetched row */
 
4675
  const unsigned char*  key_ptr,/*!< in: key value, or a prefix of a full
 
4676
        key value */
 
4677
  uint    key_len)/*!< in: length of the key val or prefix
 
4678
        in bytes */
4679
4679
{
4680
 
        return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
 
4680
  return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
4681
4681
}
4682
4682
 
4683
4683
/********************************************************************//**
4684
4684
Get the index for a handle. Does not change active index.
4685
 
@return NULL or index instance. */
 
4685
@return NULL or index instance. */
4686
4686
UNIV_INTERN
4687
4687
dict_index_t*
4688
4688
ha_innobase::innobase_get_index(
4689
4689
/*============================*/
4690
 
        uint            keynr)  /*!< in: use this index; MAX_KEY means always
4691
 
                                clustered index, even if it was internally
4692
 
                                generated by InnoDB */
 
4690
  uint    keynr)  /*!< in: use this index; MAX_KEY means always
 
4691
        clustered index, even if it was internally
 
4692
        generated by InnoDB */
4693
4693
{
4694
 
        KEY*            key = 0;
4695
 
        dict_index_t*   index = 0;
4696
 
 
4697
 
        ha_statistic_increment(&system_status_var::ha_read_key_count);
4698
 
 
4699
 
        ut_ad(user_session == ha_session());
4700
 
        ut_a(prebuilt->trx == session_to_trx(user_session));
4701
 
 
4702
 
        if (keynr != MAX_KEY && table->s->keys > 0) {
4703
 
                key = table->key_info + keynr;
4704
 
 
4705
 
                index = dict_table_get_index_on_name(prebuilt->table,
4706
 
                                                     key->name);
4707
 
        } else {
4708
 
                index = dict_table_get_first_index(prebuilt->table);
4709
 
        }
4710
 
 
4711
 
        if (!index) {
4712
 
                errmsg_printf(ERRMSG_LVL_ERROR, 
4713
 
                        "Innodb could not find key n:o %u with name %s "
4714
 
                        "from dict cache for table %s",
4715
 
                        keynr, key ? key->name : "NULL",
4716
 
                        prebuilt->table->name);
4717
 
        }
4718
 
 
4719
 
        return(index);
 
4694
  KEY*    key = 0;
 
4695
  dict_index_t* index = 0;
 
4696
 
 
4697
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
4698
 
 
4699
  ut_ad(user_session == ha_session());
 
4700
  ut_a(prebuilt->trx == session_to_trx(user_session));
 
4701
 
 
4702
  if (keynr != MAX_KEY && table->s->keys > 0) {
 
4703
    key = table->key_info + keynr;
 
4704
 
 
4705
    index = dict_table_get_index_on_name(prebuilt->table,
 
4706
                 key->name);
 
4707
  } else {
 
4708
    index = dict_table_get_first_index(prebuilt->table);
 
4709
  }
 
4710
 
 
4711
  if (!index) {
 
4712
    errmsg_printf(ERRMSG_LVL_ERROR, 
 
4713
      "Innodb could not find key n:o %u with name %s "
 
4714
      "from dict cache for table %s",
 
4715
      keynr, key ? key->name : "NULL",
 
4716
      prebuilt->table->name);
 
4717
  }
 
4718
 
 
4719
  return(index);
4720
4720
}
4721
4721
 
4722
4722
/********************************************************************//**
4723
4723
Changes the active index of a handle.
4724
 
@return 0 or error code */
 
4724
@return 0 or error code */
4725
4725
UNIV_INTERN
4726
4726
int
4727
4727
ha_innobase::change_active_index(
4728
4728
/*=============================*/
4729
 
        uint    keynr)  /*!< in: use this index; MAX_KEY means always clustered
4730
 
                        index, even if it was internally generated by
4731
 
                        InnoDB */
 
4729
  uint  keynr)  /*!< in: use this index; MAX_KEY means always clustered
 
4730
      index, even if it was internally generated by
 
4731
      InnoDB */
4732
4732
{
4733
 
        ut_ad(user_session == ha_session());
4734
 
        ut_a(prebuilt->trx == session_to_trx(user_session));
4735
 
 
4736
 
        active_index = keynr;
4737
 
 
4738
 
        prebuilt->index = innobase_get_index(keynr);
4739
 
 
4740
 
        if (UNIV_UNLIKELY(!prebuilt->index)) {
4741
 
                errmsg_printf(ERRMSG_LVL_WARN, "InnoDB: change_active_index(%u) failed",
4742
 
                                  keynr);
4743
 
                return(1);
4744
 
        }
4745
 
 
4746
 
        prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
4747
 
                                                           prebuilt->index);
4748
 
 
4749
 
        if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
4750
 
                errmsg_printf(ERRMSG_LVL_WARN,
4751
 
                                 "InnoDB: insufficient history for index %u",
4752
 
                                  keynr);
4753
 
                /* The caller seems to ignore this.  Thus, we must check
4754
 
                this again in row_search_for_mysql(). */
4755
 
                return(2);
4756
 
        }
4757
 
 
4758
 
        ut_a(prebuilt->search_tuple != 0);
4759
 
 
4760
 
        dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
4761
 
 
4762
 
        dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
4763
 
                        prebuilt->index->n_fields);
4764
 
 
4765
 
        /* MySQL changes the active index for a handle also during some
4766
 
        queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
4767
 
        and then calculates the sum. Previously we played safe and used
4768
 
        the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
4769
 
        copying. Starting from MySQL-4.1 we use a more efficient flag here. */
4770
 
 
4771
 
        build_template(prebuilt, user_session, table, ROW_MYSQL_REC_FIELDS);
4772
 
 
4773
 
        return(0);
 
4733
  ut_ad(user_session == ha_session());
 
4734
  ut_a(prebuilt->trx == session_to_trx(user_session));
 
4735
 
 
4736
  active_index = keynr;
 
4737
 
 
4738
  prebuilt->index = innobase_get_index(keynr);
 
4739
 
 
4740
  if (UNIV_UNLIKELY(!prebuilt->index)) {
 
4741
    errmsg_printf(ERRMSG_LVL_WARN, "InnoDB: change_active_index(%u) failed",
 
4742
          keynr);
 
4743
    return(1);
 
4744
  }
 
4745
 
 
4746
  prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
 
4747
                 prebuilt->index);
 
4748
 
 
4749
  if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
 
4750
    errmsg_printf(ERRMSG_LVL_WARN,
 
4751
         "InnoDB: insufficient history for index %u",
 
4752
          keynr);
 
4753
    /* The caller seems to ignore this.  Thus, we must check
 
4754
    this again in row_search_for_mysql(). */
 
4755
    return(2);
 
4756
  }
 
4757
 
 
4758
  ut_a(prebuilt->search_tuple != 0);
 
4759
 
 
4760
  dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
 
4761
 
 
4762
  dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
 
4763
      prebuilt->index->n_fields);
 
4764
 
 
4765
  /* MySQL changes the active index for a handle also during some
 
4766
  queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
 
4767
  and then calculates the sum. Previously we played safe and used
 
4768
  the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
 
4769
  copying. Starting from MySQL-4.1 we use a more efficient flag here. */
 
4770
 
 
4771
  build_template(prebuilt, user_session, table, ROW_MYSQL_REC_FIELDS);
 
4772
 
 
4773
  return(0);
4774
4774
}
4775
4775
 
4776
4776
/**********************************************************************//**
4777
4777
Positions an index cursor to the index specified in keynr. Fetches the
4778
4778
row if any.
4779
4779
??? This is only used to read whole keys ???
4780
 
@return error number or 0 */
 
4780
@return error number or 0 */
4781
4781
UNIV_INTERN
4782
4782
int
4783
4783
ha_innobase::index_read_idx(
4784
4784
/*========================*/
4785
 
        unsigned char*  buf,            /*!< in/out: buffer for the returned
4786
 
                                        row */
4787
 
        uint            keynr,          /*!< in: use this index */
4788
 
        const unsigned char*    key,    /*!< in: key value; if this is NULL
4789
 
                                        we position the cursor at the
4790
 
                                        start or end of index */
4791
 
        uint            key_len,        /*!< in: key value length */
4792
 
        enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
 
4785
  unsigned char*  buf,    /*!< in/out: buffer for the returned
 
4786
          row */
 
4787
  uint    keynr,    /*!< in: use this index */
 
4788
  const unsigned char*  key,  /*!< in: key value; if this is NULL
 
4789
          we position the cursor at the
 
4790
          start or end of index */
 
4791
  uint    key_len,  /*!< in: key value length */
 
4792
  enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
4793
4793
{
4794
 
        if (change_active_index(keynr)) {
4795
 
 
4796
 
                return(1);
4797
 
        }
4798
 
 
4799
 
        return(index_read(buf, key, key_len, find_flag));
 
4794
  if (change_active_index(keynr)) {
 
4795
 
 
4796
    return(1);
 
4797
  }
 
4798
 
 
4799
  return(index_read(buf, key, key_len, find_flag));
4800
4800
}
4801
4801
 
4802
4802
/***********************************************************************//**
4803
4803
Reads the next or previous row from a cursor, which must have previously been
4804
4804
positioned using index_read.
4805
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4805
@return 0, HA_ERR_END_OF_FILE, or error number */
4806
4806
UNIV_INTERN
4807
4807
int
4808
4808
ha_innobase::general_fetch(
4809
4809
/*=======================*/
4810
 
        unsigned char*  buf,    /*!< in/out: buffer for next row in MySQL
4811
 
                                format */
4812
 
        uint    direction,      /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
4813
 
        uint    match_mode)     /*!< in: 0, ROW_SEL_EXACT, or
4814
 
                                ROW_SEL_EXACT_PREFIX */
 
4810
  unsigned char*  buf,  /*!< in/out: buffer for next row in MySQL
 
4811
        format */
 
4812
  uint  direction,  /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
 
4813
  uint  match_mode) /*!< in: 0, ROW_SEL_EXACT, or
 
4814
        ROW_SEL_EXACT_PREFIX */
4815
4815
{
4816
 
        ulint           ret;
4817
 
        int             error   = 0;
4818
 
 
4819
 
        ut_a(prebuilt->trx == session_to_trx(user_session));
4820
 
 
4821
 
        innodb_srv_conc_enter_innodb(prebuilt->trx);
4822
 
 
4823
 
        ret = row_search_for_mysql(
4824
 
                (byte*)buf, 0, prebuilt, match_mode, direction);
4825
 
 
4826
 
        innodb_srv_conc_exit_innodb(prebuilt->trx);
4827
 
 
4828
 
        switch (ret) {
4829
 
        case DB_SUCCESS:
4830
 
                error = 0;
4831
 
                table->status = 0;
4832
 
                break;
4833
 
        case DB_RECORD_NOT_FOUND:
4834
 
                error = HA_ERR_END_OF_FILE;
4835
 
                table->status = STATUS_NOT_FOUND;
4836
 
                break;
4837
 
        case DB_END_OF_INDEX:
4838
 
                error = HA_ERR_END_OF_FILE;
4839
 
                table->status = STATUS_NOT_FOUND;
4840
 
                break;
4841
 
        default:
4842
 
                error = convert_error_code_to_mysql(
4843
 
                        (int) ret, prebuilt->table->flags, user_session);
4844
 
                table->status = STATUS_NOT_FOUND;
4845
 
                break;
4846
 
        }
4847
 
 
4848
 
        return(error);
 
4816
  ulint   ret;
 
4817
  int   error = 0;
 
4818
 
 
4819
  ut_a(prebuilt->trx == session_to_trx(user_session));
 
4820
 
 
4821
  innodb_srv_conc_enter_innodb(prebuilt->trx);
 
4822
 
 
4823
  ret = row_search_for_mysql(
 
4824
    (byte*)buf, 0, prebuilt, match_mode, direction);
 
4825
 
 
4826
  innodb_srv_conc_exit_innodb(prebuilt->trx);
 
4827
 
 
4828
  switch (ret) {
 
4829
  case DB_SUCCESS:
 
4830
    error = 0;
 
4831
    table->status = 0;
 
4832
    break;
 
4833
  case DB_RECORD_NOT_FOUND:
 
4834
    error = HA_ERR_END_OF_FILE;
 
4835
    table->status = STATUS_NOT_FOUND;
 
4836
    break;
 
4837
  case DB_END_OF_INDEX:
 
4838
    error = HA_ERR_END_OF_FILE;
 
4839
    table->status = STATUS_NOT_FOUND;
 
4840
    break;
 
4841
  default:
 
4842
    error = convert_error_code_to_mysql(
 
4843
      (int) ret, prebuilt->table->flags, user_session);
 
4844
    table->status = STATUS_NOT_FOUND;
 
4845
    break;
 
4846
  }
 
4847
 
 
4848
  return(error);
4849
4849
}
4850
4850
 
4851
4851
/***********************************************************************//**
4852
4852
Reads the next row from a cursor, which must have previously been
4853
4853
positioned using index_read.
4854
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4854
@return 0, HA_ERR_END_OF_FILE, or error number */
4855
4855
UNIV_INTERN
4856
4856
int
4857
4857
ha_innobase::index_next(
4858
4858
/*====================*/
4859
 
        unsigned char*  buf)    /*!< in/out: buffer for next row in MySQL
4860
 
                                format */
 
4859
  unsigned char*  buf)  /*!< in/out: buffer for next row in MySQL
 
4860
        format */
4861
4861
{
4862
 
        ha_statistic_increment(&system_status_var::ha_read_next_count);
 
4862
  ha_statistic_increment(&system_status_var::ha_read_next_count);
4863
4863
 
4864
 
        return(general_fetch(buf, ROW_SEL_NEXT, 0));
 
4864
  return(general_fetch(buf, ROW_SEL_NEXT, 0));
4865
4865
}
4866
4866
 
4867
4867
/*******************************************************************//**
4868
4868
Reads the next row matching to the key value given as the parameter.
4869
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4869
@return 0, HA_ERR_END_OF_FILE, or error number */
4870
4870
UNIV_INTERN
4871
4871
int
4872
4872
ha_innobase::index_next_same(
4873
4873
/*=========================*/
4874
 
        unsigned char*          buf,    /*!< in/out: buffer for the row */
4875
 
        const unsigned char*    ,       /*!< in: key value */
4876
 
        uint            )       /*!< in: key value length */
 
4874
  unsigned char*    buf,  /*!< in/out: buffer for the row */
 
4875
  const unsigned char*  , /*!< in: key value */
 
4876
  uint    ) /*!< in: key value length */
4877
4877
{
4878
 
        ha_statistic_increment(&system_status_var::ha_read_next_count);
 
4878
  ha_statistic_increment(&system_status_var::ha_read_next_count);
4879
4879
 
4880
 
        return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
 
4880
  return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
4881
4881
}
4882
4882
 
4883
4883
/***********************************************************************//**
4884
4884
Reads the previous row from a cursor, which must have previously been
4885
4885
positioned using index_read.
4886
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4886
@return 0, HA_ERR_END_OF_FILE, or error number */
4887
4887
UNIV_INTERN
4888
4888
int
4889
4889
ha_innobase::index_prev(
4890
4890
/*====================*/
4891
 
        unsigned char*  buf)    /*!< in/out: buffer for previous row in MySQL format */
 
4891
  unsigned char*  buf)  /*!< in/out: buffer for previous row in MySQL format */
4892
4892
{
4893
 
        ha_statistic_increment(&system_status_var::ha_read_prev_count);
 
4893
  ha_statistic_increment(&system_status_var::ha_read_prev_count);
4894
4894
 
4895
 
        return(general_fetch(buf, ROW_SEL_PREV, 0));
 
4895
  return(general_fetch(buf, ROW_SEL_PREV, 0));
4896
4896
}
4897
4897
 
4898
4898
/********************************************************************//**
4899
4899
Positions a cursor on the first record in an index and reads the
4900
4900
corresponding row to buf.
4901
 
@return 0, HA_ERR_END_OF_FILE, or error code */
 
4901
@return 0, HA_ERR_END_OF_FILE, or error code */
4902
4902
UNIV_INTERN
4903
4903
int
4904
4904
ha_innobase::index_first(
4905
4905
/*=====================*/
4906
 
        unsigned char*  buf)    /*!< in/out: buffer for the row */
 
4906
  unsigned char*  buf)  /*!< in/out: buffer for the row */
4907
4907
{
4908
 
        int     error;
4909
 
 
4910
 
        ha_statistic_increment(&system_status_var::ha_read_first_count);
4911
 
 
4912
 
        error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
4913
 
 
4914
 
        /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
4915
 
 
4916
 
        if (error == HA_ERR_KEY_NOT_FOUND) {
4917
 
                error = HA_ERR_END_OF_FILE;
4918
 
        }
4919
 
 
4920
 
        return(error);
 
4908
  int error;
 
4909
 
 
4910
  ha_statistic_increment(&system_status_var::ha_read_first_count);
 
4911
 
 
4912
  error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
 
4913
 
 
4914
  /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
 
4915
 
 
4916
  if (error == HA_ERR_KEY_NOT_FOUND) {
 
4917
    error = HA_ERR_END_OF_FILE;
 
4918
  }
 
4919
 
 
4920
  return(error);
4921
4921
}
4922
4922
 
4923
4923
/********************************************************************//**
4924
4924
Positions a cursor on the last record in an index and reads the
4925
4925
corresponding row to buf.
4926
 
@return 0, HA_ERR_END_OF_FILE, or error code */
 
4926
@return 0, HA_ERR_END_OF_FILE, or error code */
4927
4927
UNIV_INTERN
4928
4928
int
4929
4929
ha_innobase::index_last(
4930
4930
/*====================*/
4931
 
        unsigned char*  buf)    /*!< in/out: buffer for the row */
 
4931
  unsigned char*  buf)  /*!< in/out: buffer for the row */
4932
4932
{
4933
 
        int     error;
4934
 
 
4935
 
        ha_statistic_increment(&system_status_var::ha_read_last_count);
4936
 
 
4937
 
        error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
4938
 
 
4939
 
        /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
4940
 
 
4941
 
        if (error == HA_ERR_KEY_NOT_FOUND) {
4942
 
                error = HA_ERR_END_OF_FILE;
4943
 
        }
4944
 
 
4945
 
        return(error);
 
4933
  int error;
 
4934
 
 
4935
  ha_statistic_increment(&system_status_var::ha_read_last_count);
 
4936
 
 
4937
  error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
 
4938
 
 
4939
  /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
 
4940
 
 
4941
  if (error == HA_ERR_KEY_NOT_FOUND) {
 
4942
    error = HA_ERR_END_OF_FILE;
 
4943
  }
 
4944
 
 
4945
  return(error);
4946
4946
}
4947
4947
 
4948
4948
/****************************************************************//**
4949
4949
Initialize a table scan.
4950
 
@return 0 or error number */
 
4950
@return 0 or error number */
4951
4951
UNIV_INTERN
4952
4952
int
4953
4953
ha_innobase::rnd_init(
4954
4954
/*==================*/
4955
 
        bool    scan)   /*!< in: TRUE if table/index scan FALSE otherwise */
 
4955
  bool  scan) /*!< in: TRUE if table/index scan FALSE otherwise */
4956
4956
{
4957
 
        int     err;
4958
 
 
4959
 
        /* Store the active index value so that we can restore the original
4960
 
        value after a scan */
4961
 
 
4962
 
        if (prebuilt->clust_index_was_generated) {
4963
 
                err = change_active_index(MAX_KEY);
4964
 
        } else {
4965
 
                err = change_active_index(primary_key);
4966
 
        }
4967
 
 
4968
 
        /* Don't use semi-consistent read in random row reads (by position).
4969
 
        This means we must disable semi_consistent_read if scan is false */
4970
 
 
4971
 
        if (!scan) {
4972
 
                try_semi_consistent_read(0);
4973
 
        }
4974
 
 
4975
 
        start_of_scan = 1;
4976
 
 
4977
 
        return(err);
 
4957
  int err;
 
4958
 
 
4959
  /* Store the active index value so that we can restore the original
 
4960
  value after a scan */
 
4961
 
 
4962
  if (prebuilt->clust_index_was_generated) {
 
4963
    err = change_active_index(MAX_KEY);
 
4964
  } else {
 
4965
    err = change_active_index(primary_key);
 
4966
  }
 
4967
 
 
4968
  /* Don't use semi-consistent read in random row reads (by position).
 
4969
  This means we must disable semi_consistent_read if scan is false */
 
4970
 
 
4971
  if (!scan) {
 
4972
    try_semi_consistent_read(0);
 
4973
  }
 
4974
 
 
4975
  start_of_scan = 1;
 
4976
 
 
4977
  return(err);
4978
4978
}
4979
4979
 
4980
4980
/*****************************************************************//**
4981
4981
Ends a table scan.
4982
 
@return 0 or error number */
 
4982
@return 0 or error number */
4983
4983
UNIV_INTERN
4984
4984
int
4985
4985
ha_innobase::rnd_end(void)
4986
4986
/*======================*/
4987
4987
{
4988
 
        return(index_end());
 
4988
  return(index_end());
4989
4989
}
4990
4990
 
4991
4991
/*****************************************************************//**
4992
4992
Reads the next row in a table scan (also used to read the FIRST row
4993
4993
in a table scan).
4994
 
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4994
@return 0, HA_ERR_END_OF_FILE, or error number */
4995
4995
UNIV_INTERN
4996
4996
int
4997
4997
ha_innobase::rnd_next(
4998
4998
/*==================*/
4999
 
        unsigned char*  buf)    /*!< in/out: returns the row in this buffer,
5000
 
                        in MySQL format */
 
4999
  unsigned char*  buf)  /*!< in/out: returns the row in this buffer,
 
5000
      in MySQL format */
5001
5001
{
5002
 
        int     error;
5003
 
 
5004
 
        ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
5005
 
 
5006
 
        if (start_of_scan) {
5007
 
                error = index_first(buf);
5008
 
 
5009
 
                if (error == HA_ERR_KEY_NOT_FOUND) {
5010
 
                        error = HA_ERR_END_OF_FILE;
5011
 
                }
5012
 
 
5013
 
                start_of_scan = 0;
5014
 
        } else {
5015
 
                error = general_fetch(buf, ROW_SEL_NEXT, 0);
5016
 
        }
5017
 
 
5018
 
        return(error);
 
5002
  int error;
 
5003
 
 
5004
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
 
5005
 
 
5006
  if (start_of_scan) {
 
5007
    error = index_first(buf);
 
5008
 
 
5009
    if (error == HA_ERR_KEY_NOT_FOUND) {
 
5010
      error = HA_ERR_END_OF_FILE;
 
5011
    }
 
5012
 
 
5013
    start_of_scan = 0;
 
5014
  } else {
 
5015
    error = general_fetch(buf, ROW_SEL_NEXT, 0);
 
5016
  }
 
5017
 
 
5018
  return(error);
5019
5019
}
5020
5020
 
5021
5021
/**********************************************************************//**
5022
5022
Fetches a row from the table based on a row reference.
5023
 
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
 
5023
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
5024
5024
UNIV_INTERN
5025
5025
int
5026
5026
ha_innobase::rnd_pos(
5027
5027
/*=================*/
5028
 
        unsigned char*  buf,    /*!< in/out: buffer for the row */
5029
 
        unsigned char*  pos)    /*!< in: primary key value of the row in the
5030
 
                        MySQL format, or the row id if the clustered
5031
 
                        index was internally generated by InnoDB; the
5032
 
                        length of data in pos has to be ref_length */
 
5028
  unsigned char*  buf,  /*!< in/out: buffer for the row */
 
5029
  unsigned char*  pos)  /*!< in: primary key value of the row in the
 
5030
      MySQL format, or the row id if the clustered
 
5031
      index was internally generated by InnoDB; the
 
5032
      length of data in pos has to be ref_length */
5033
5033
{
5034
 
        int             error;
5035
 
        uint            keynr   = active_index;
5036
 
 
5037
 
        ha_statistic_increment(&system_status_var::ha_read_rnd_count);
5038
 
 
5039
 
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
5040
 
 
5041
 
        if (prebuilt->clust_index_was_generated) {
5042
 
                /* No primary key was defined for the table and we
5043
 
                generated the clustered index from the row id: the
5044
 
                row reference is the row id, not any key value
5045
 
                that MySQL knows of */
5046
 
 
5047
 
                error = change_active_index(MAX_KEY);
5048
 
        } else {
5049
 
                error = change_active_index(primary_key);
5050
 
        }
5051
 
 
5052
 
        if (error) {
5053
 
                return(error);
5054
 
        }
5055
 
 
5056
 
        /* Note that we assume the length of the row reference is fixed
5057
 
        for the table, and it is == ref_length */
5058
 
 
5059
 
        error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
5060
 
 
5061
 
        if (error) {
5062
 
        }
5063
 
 
5064
 
        change_active_index(keynr);
5065
 
 
5066
 
        return(error);
 
5034
  int   error;
 
5035
  uint    keynr = active_index;
 
5036
 
 
5037
  ha_statistic_increment(&system_status_var::ha_read_rnd_count);
 
5038
 
 
5039
  ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
5040
 
 
5041
  if (prebuilt->clust_index_was_generated) {
 
5042
    /* No primary key was defined for the table and we
 
5043
    generated the clustered index from the row id: the
 
5044
    row reference is the row id, not any key value
 
5045
    that MySQL knows of */
 
5046
 
 
5047
    error = change_active_index(MAX_KEY);
 
5048
  } else {
 
5049
    error = change_active_index(primary_key);
 
5050
  }
 
5051
 
 
5052
  if (error) {
 
5053
    return(error);
 
5054
  }
 
5055
 
 
5056
  /* Note that we assume the length of the row reference is fixed
 
5057
  for the table, and it is == ref_length */
 
5058
 
 
5059
  error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
 
5060
 
 
5061
  if (error) {
 
5062
  }
 
5063
 
 
5064
  change_active_index(keynr);
 
5065
 
 
5066
  return(error);
5067
5067
}
5068
5068
 
5069
5069
/*********************************************************************//**
5078
5078
void
5079
5079
ha_innobase::position(
5080
5080
/*==================*/
5081
 
        const unsigned char*    record) /*!< in: row in MySQL format */
 
5081
  const unsigned char*  record) /*!< in: row in MySQL format */
5082
5082
{
5083
 
        uint            len;
5084
 
 
5085
 
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
5086
 
 
5087
 
        if (prebuilt->clust_index_was_generated) {
5088
 
                /* No primary key was defined for the table and we
5089
 
                generated the clustered index from row id: the
5090
 
                row reference will be the row id, not any key value
5091
 
                that MySQL knows of */
5092
 
 
5093
 
                len = DATA_ROW_ID_LEN;
5094
 
 
5095
 
                memcpy(ref, prebuilt->row_id, len);
5096
 
        } else {
5097
 
                len = store_key_val_for_row(primary_key, (char*)ref,
5098
 
                                                         ref_length, record);
5099
 
        }
5100
 
 
5101
 
        /* We assume that the 'ref' value len is always fixed for the same
5102
 
        table. */
5103
 
 
5104
 
        if (len != ref_length) {
5105
 
          errmsg_printf(ERRMSG_LVL_ERROR, "Stored ref len is %lu, but table ref len is %lu",
5106
 
                          (ulong) len, (ulong) ref_length);
5107
 
        }
 
5083
  uint    len;
 
5084
 
 
5085
  ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
5086
 
 
5087
  if (prebuilt->clust_index_was_generated) {
 
5088
    /* No primary key was defined for the table and we
 
5089
    generated the clustered index from row id: the
 
5090
    row reference will be the row id, not any key value
 
5091
    that MySQL knows of */
 
5092
 
 
5093
    len = DATA_ROW_ID_LEN;
 
5094
 
 
5095
    memcpy(ref, prebuilt->row_id, len);
 
5096
  } else {
 
5097
    len = store_key_val_for_row(primary_key, (char*)ref,
 
5098
               ref_length, record);
 
5099
  }
 
5100
 
 
5101
  /* We assume that the 'ref' value len is always fixed for the same
 
5102
  table. */
 
5103
 
 
5104
  if (len != ref_length) {
 
5105
    errmsg_printf(ERRMSG_LVL_ERROR, "Stored ref len is %lu, but table ref len is %lu",
 
5106
        (ulong) len, (ulong) ref_length);
 
5107
  }
5108
5108
}
5109
5109
 
5110
5110
 
5114
5114
int
5115
5115
create_table_def(
5116
5116
/*=============*/
5117
 
        trx_t*          trx,            /*!< in: InnoDB transaction handle */
5118
 
        Table*          form,           /*!< in: information on table
5119
 
                                        columns and indexes */
5120
 
        const char*     table_name,     /*!< in: table name */
5121
 
        const char*     path_of_temp_table,/*!< in: if this is a table explicitly
5122
 
                                        created by the user with the
5123
 
                                        TEMPORARY keyword, then this
5124
 
                                        parameter is the dir path where the
5125
 
                                        table should be placed if we create
5126
 
                                        an .ibd file for it (no .ibd extension
5127
 
                                        in the path, though); otherwise this
5128
 
                                        is NULL */
5129
 
        ulint           flags)          /*!< in: table flags */
 
5117
  trx_t*    trx,    /*!< in: InnoDB transaction handle */
 
5118
  Table*    form,   /*!< in: information on table
 
5119
          columns and indexes */
 
5120
  const char* table_name, /*!< in: table name */
 
5121
  const char* path_of_temp_table,/*!< in: if this is a table explicitly
 
5122
          created by the user with the
 
5123
          TEMPORARY keyword, then this
 
5124
          parameter is the dir path where the
 
5125
          table should be placed if we create
 
5126
          an .ibd file for it (no .ibd extension
 
5127
          in the path, though); otherwise this
 
5128
          is NULL */
 
5129
  ulint   flags)    /*!< in: table flags */
5130
5130
{
5131
 
        Field*          field;
5132
 
        dict_table_t*   table;
5133
 
        ulint           n_cols;
5134
 
        int             error;
5135
 
        ulint           col_type;
5136
 
        ulint           col_len;
5137
 
        ulint           nulls_allowed;
5138
 
        ulint           unsigned_type;
5139
 
        ulint           binary_type;
5140
 
        ulint           long_true_varchar;
5141
 
        ulint           charset_no;
5142
 
        ulint           i;
5143
 
 
5144
 
        n_cols = form->s->fields;
5145
 
 
5146
 
        /* We pass 0 as the space id, and determine at a lower level the space
5147
 
        id where to store the table */
5148
 
 
5149
 
        table = dict_mem_table_create(table_name, 0, n_cols, flags);
5150
 
 
5151
 
        if (path_of_temp_table) {
5152
 
                table->dir_path_of_temp_table =
5153
 
                        mem_heap_strdup(table->heap, path_of_temp_table);
5154
 
        }
5155
 
 
5156
 
        for (i = 0; i < n_cols; i++) {
5157
 
                field = form->field[i];
5158
 
 
5159
 
                col_type = get_innobase_type_from_mysql_type(&unsigned_type,
5160
 
                                                                        field);
5161
 
                if (field->null_ptr) {
5162
 
                        nulls_allowed = 0;
5163
 
                } else {
5164
 
                        nulls_allowed = DATA_NOT_NULL;
5165
 
                }
5166
 
 
5167
 
                if (field->binary()) {
5168
 
                        binary_type = DATA_BINARY_TYPE;
5169
 
                } else {
5170
 
                        binary_type = 0;
5171
 
                }
5172
 
 
5173
 
                charset_no = 0;
5174
 
 
5175
 
                if (dtype_is_string_type(col_type)) {
5176
 
 
5177
 
                        charset_no = (ulint)field->charset()->number;
5178
 
 
5179
 
                        if (UNIV_UNLIKELY(charset_no >= 256)) {
5180
 
                                /* in data0type.h we assume that the
5181
 
                                number fits in one byte in prtype */
5182
 
                                push_warning_printf(
5183
 
                                        (Session*) trx->mysql_thd,
5184
 
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5185
 
                                        ER_CANT_CREATE_TABLE,
5186
 
                                        "In InnoDB, charset-collation codes"
5187
 
                                        " must be below 256."
5188
 
                                        " Unsupported code %lu.",
5189
 
                                        (ulong) charset_no);
5190
 
                                return(ER_CANT_CREATE_TABLE);
5191
 
                        }
5192
 
                }
5193
 
 
5194
 
                ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
5195
 
                                           that this fits in one byte */
5196
 
                col_len = field->pack_length();
5197
 
 
5198
 
                /* The MySQL pack length contains 1 or 2 bytes length field
5199
 
                for a true VARCHAR. Let us subtract that, so that the InnoDB
5200
 
                column length in the InnoDB data dictionary is the real
5201
 
                maximum byte length of the actual data. */
5202
 
 
5203
 
                long_true_varchar = 0;
5204
 
 
5205
 
                if (field->type() == DRIZZLE_TYPE_VARCHAR) {
5206
 
                        col_len -= ((Field_varstring*)field)->length_bytes;
5207
 
 
5208
 
                        if (((Field_varstring*)field)->length_bytes == 2) {
5209
 
                                long_true_varchar = DATA_LONG_TRUE_VARCHAR;
5210
 
                        }
5211
 
                }
5212
 
 
5213
 
                dict_mem_table_add_col(table, table->heap,
5214
 
                        (char*) field->field_name,
5215
 
                        col_type,
5216
 
                        dtype_form_prtype(
5217
 
                                (ulint)field->type()
5218
 
                                | nulls_allowed | unsigned_type
5219
 
                                | binary_type | long_true_varchar,
5220
 
                                charset_no),
5221
 
                        col_len);
5222
 
        }
5223
 
 
5224
 
        error = row_create_table_for_mysql(table, trx);
5225
 
 
5226
 
        error = convert_error_code_to_mysql(error, flags, NULL);
5227
 
 
5228
 
        return(error);
 
5131
  Field*    field;
 
5132
  dict_table_t* table;
 
5133
  ulint   n_cols;
 
5134
  int   error;
 
5135
  ulint   col_type;
 
5136
  ulint   col_len;
 
5137
  ulint   nulls_allowed;
 
5138
  ulint   unsigned_type;
 
5139
  ulint   binary_type;
 
5140
  ulint   long_true_varchar;
 
5141
  ulint   charset_no;
 
5142
  ulint   i;
 
5143
 
 
5144
  n_cols = form->s->fields;
 
5145
 
 
5146
  /* We pass 0 as the space id, and determine at a lower level the space
 
5147
  id where to store the table */
 
5148
 
 
5149
  table = dict_mem_table_create(table_name, 0, n_cols, flags);
 
5150
 
 
5151
  if (path_of_temp_table) {
 
5152
    table->dir_path_of_temp_table =
 
5153
      mem_heap_strdup(table->heap, path_of_temp_table);
 
5154
  }
 
5155
 
 
5156
  for (i = 0; i < n_cols; i++) {
 
5157
    field = form->field[i];
 
5158
 
 
5159
    col_type = get_innobase_type_from_mysql_type(&unsigned_type,
 
5160
                  field);
 
5161
    if (field->null_ptr) {
 
5162
      nulls_allowed = 0;
 
5163
    } else {
 
5164
      nulls_allowed = DATA_NOT_NULL;
 
5165
    }
 
5166
 
 
5167
    if (field->binary()) {
 
5168
      binary_type = DATA_BINARY_TYPE;
 
5169
    } else {
 
5170
      binary_type = 0;
 
5171
    }
 
5172
 
 
5173
    charset_no = 0;
 
5174
 
 
5175
    if (dtype_is_string_type(col_type)) {
 
5176
 
 
5177
      charset_no = (ulint)field->charset()->number;
 
5178
 
 
5179
      if (UNIV_UNLIKELY(charset_no >= 256)) {
 
5180
        /* in data0type.h we assume that the
 
5181
        number fits in one byte in prtype */
 
5182
        push_warning_printf(
 
5183
          (Session*) trx->mysql_thd,
 
5184
          DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5185
          ER_CANT_CREATE_TABLE,
 
5186
          "In InnoDB, charset-collation codes"
 
5187
          " must be below 256."
 
5188
          " Unsupported code %lu.",
 
5189
          (ulong) charset_no);
 
5190
        return(ER_CANT_CREATE_TABLE);
 
5191
      }
 
5192
    }
 
5193
 
 
5194
    ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
 
5195
             that this fits in one byte */
 
5196
    col_len = field->pack_length();
 
5197
 
 
5198
    /* The MySQL pack length contains 1 or 2 bytes length field
 
5199
    for a true VARCHAR. Let us subtract that, so that the InnoDB
 
5200
    column length in the InnoDB data dictionary is the real
 
5201
    maximum byte length of the actual data. */
 
5202
 
 
5203
    long_true_varchar = 0;
 
5204
 
 
5205
    if (field->type() == DRIZZLE_TYPE_VARCHAR) {
 
5206
      col_len -= ((Field_varstring*)field)->length_bytes;
 
5207
 
 
5208
      if (((Field_varstring*)field)->length_bytes == 2) {
 
5209
        long_true_varchar = DATA_LONG_TRUE_VARCHAR;
 
5210
      }
 
5211
    }
 
5212
 
 
5213
    dict_mem_table_add_col(table, table->heap,
 
5214
      (char*) field->field_name,
 
5215
      col_type,
 
5216
      dtype_form_prtype(
 
5217
        (ulint)field->type()
 
5218
        | nulls_allowed | unsigned_type
 
5219
        | binary_type | long_true_varchar,
 
5220
        charset_no),
 
5221
      col_len);
 
5222
  }
 
5223
 
 
5224
  error = row_create_table_for_mysql(table, trx);
 
5225
 
 
5226
  error = convert_error_code_to_mysql(error, flags, NULL);
 
5227
 
 
5228
  return(error);
5229
5229
}
5230
5230
 
5231
5231
/*****************************************************************//**
5234
5234
int
5235
5235
create_index(
5236
5236
/*=========*/
5237
 
        trx_t*          trx,            /*!< in: InnoDB transaction handle */
5238
 
        Table*          form,           /*!< in: information on table
5239
 
                                        columns and indexes */
5240
 
        ulint           flags,          /*!< in: InnoDB table flags */
5241
 
        const char*     table_name,     /*!< in: table name */
5242
 
        uint            key_num)        /*!< in: index number */
 
5237
  trx_t*    trx,    /*!< in: InnoDB transaction handle */
 
5238
  Table*    form,   /*!< in: information on table
 
5239
          columns and indexes */
 
5240
  ulint   flags,    /*!< in: InnoDB table flags */
 
5241
  const char* table_name, /*!< in: table name */
 
5242
  uint    key_num)  /*!< in: index number */
5243
5243
{
5244
 
        Field*          field;
5245
 
        dict_index_t*   index;
5246
 
        int             error;
5247
 
        ulint           n_fields;
5248
 
        KEY*            key;
5249
 
        KEY_PART_INFO*  key_part;
5250
 
        ulint           ind_type;
5251
 
        ulint           col_type;
5252
 
        ulint           prefix_len;
5253
 
        ulint           is_unsigned;
5254
 
        ulint           i;
5255
 
        ulint           j;
5256
 
        ulint*          field_lengths;
5257
 
 
5258
 
        key = form->key_info + key_num;
5259
 
 
5260
 
        n_fields = key->key_parts;
5261
 
 
5262
 
        ind_type = 0;
5263
 
 
5264
 
        if (key_num == form->s->primary_key) {
5265
 
                ind_type = ind_type | DICT_CLUSTERED;
5266
 
        }
5267
 
 
5268
 
        if (key->flags & HA_NOSAME ) {
5269
 
                ind_type = ind_type | DICT_UNIQUE;
5270
 
        }
5271
 
 
5272
 
        /* We pass 0 as the space id, and determine at a lower level the space
5273
 
        id where to store the table */
5274
 
 
5275
 
        index = dict_mem_index_create(table_name, key->name, 0,
5276
 
                                      ind_type, n_fields);
5277
 
 
5278
 
        field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
5279
 
 
5280
 
        for (i = 0; i < n_fields; i++) {
5281
 
                key_part = key->key_part + i;
5282
 
 
5283
 
                /* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
5284
 
                field in an index: we only store a specified number of first
5285
 
                bytes of the column to the index field.) The flag does not
5286
 
                seem to be properly set by MySQL. Let us fall back on testing
5287
 
                the length of the key part versus the column. */
5288
 
 
5289
 
                field = NULL;
5290
 
                for (j = 0; j < form->s->fields; j++) {
5291
 
 
5292
 
                        field = form->field[j];
5293
 
 
5294
 
                        if (0 == innobase_strcasecmp(
5295
 
                                        field->field_name,
5296
 
                                        key_part->field->field_name)) {
5297
 
                                /* Found the corresponding column */
5298
 
 
5299
 
                                break;
5300
 
                        }
5301
 
                }
5302
 
 
5303
 
                ut_a(j < form->s->fields);
5304
 
 
5305
 
                col_type = get_innobase_type_from_mysql_type(
5306
 
                                        &is_unsigned, key_part->field);
5307
 
 
5308
 
                if (DATA_BLOB == col_type
5309
 
                        || (key_part->length < field->pack_length()
5310
 
                                && field->type() != DRIZZLE_TYPE_VARCHAR)
5311
 
                        || (field->type() == DRIZZLE_TYPE_VARCHAR
5312
 
                                && key_part->length < field->pack_length()
5313
 
                                - ((Field_varstring*)field)->length_bytes)) {
5314
 
 
5315
 
                        prefix_len = key_part->length;
5316
 
 
5317
 
                        if (col_type == DATA_INT
5318
 
                                || col_type == DATA_FLOAT
5319
 
                                || col_type == DATA_DOUBLE
5320
 
                                || col_type == DATA_DECIMAL) {
5321
 
                                errmsg_printf(ERRMSG_LVL_ERROR, 
5322
 
                                        "MySQL is trying to create a column "
5323
 
                                        "prefix index field, on an "
5324
 
                                        "inappropriate data type. Table "
5325
 
                                        "name %s, column name %s.",
5326
 
                                        table_name,
5327
 
                                        key_part->field->field_name);
5328
 
 
5329
 
                                prefix_len = 0;
5330
 
                        }
5331
 
                } else {
5332
 
                        prefix_len = 0;
5333
 
                }
5334
 
 
5335
 
                field_lengths[i] = key_part->length;
5336
 
 
5337
 
                dict_mem_index_add_field(index,
5338
 
                        (char*) key_part->field->field_name, prefix_len);
5339
 
        }
5340
 
 
5341
 
        /* Even though we've defined max_supported_key_part_length, we
5342
 
        still do our own checking using field_lengths to be absolutely
5343
 
        sure we don't create too long indexes. */
5344
 
        error = row_create_index_for_mysql(index, trx, field_lengths);
5345
 
 
5346
 
        error = convert_error_code_to_mysql(error, flags, NULL);
5347
 
 
5348
 
        free(field_lengths);
5349
 
 
5350
 
        return(error);
 
5244
  Field*    field;
 
5245
  dict_index_t* index;
 
5246
  int   error;
 
5247
  ulint   n_fields;
 
5248
  KEY*    key;
 
5249
  KEY_PART_INFO*  key_part;
 
5250
  ulint   ind_type;
 
5251
  ulint   col_type;
 
5252
  ulint   prefix_len;
 
5253
  ulint   is_unsigned;
 
5254
  ulint   i;
 
5255
  ulint   j;
 
5256
  ulint*    field_lengths;
 
5257
 
 
5258
  key = form->key_info + key_num;
 
5259
 
 
5260
  n_fields = key->key_parts;
 
5261
 
 
5262
  ind_type = 0;
 
5263
 
 
5264
  if (key_num == form->s->primary_key) {
 
5265
    ind_type = ind_type | DICT_CLUSTERED;
 
5266
  }
 
5267
 
 
5268
  if (key->flags & HA_NOSAME ) {
 
5269
    ind_type = ind_type | DICT_UNIQUE;
 
5270
  }
 
5271
 
 
5272
  /* We pass 0 as the space id, and determine at a lower level the space
 
5273
  id where to store the table */
 
5274
 
 
5275
  index = dict_mem_index_create(table_name, key->name, 0,
 
5276
              ind_type, n_fields);
 
5277
 
 
5278
  field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
 
5279
 
 
5280
  for (i = 0; i < n_fields; i++) {
 
5281
    key_part = key->key_part + i;
 
5282
 
 
5283
    /* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
 
5284
    field in an index: we only store a specified number of first
 
5285
    bytes of the column to the index field.) The flag does not
 
5286
    seem to be properly set by MySQL. Let us fall back on testing
 
5287
    the length of the key part versus the column. */
 
5288
 
 
5289
    field = NULL;
 
5290
    for (j = 0; j < form->s->fields; j++) {
 
5291
 
 
5292
      field = form->field[j];
 
5293
 
 
5294
      if (0 == innobase_strcasecmp(
 
5295
          field->field_name,
 
5296
          key_part->field->field_name)) {
 
5297
        /* Found the corresponding column */
 
5298
 
 
5299
        break;
 
5300
      }
 
5301
    }
 
5302
 
 
5303
    ut_a(j < form->s->fields);
 
5304
 
 
5305
    col_type = get_innobase_type_from_mysql_type(
 
5306
          &is_unsigned, key_part->field);
 
5307
 
 
5308
    if (DATA_BLOB == col_type
 
5309
      || (key_part->length < field->pack_length()
 
5310
        && field->type() != DRIZZLE_TYPE_VARCHAR)
 
5311
      || (field->type() == DRIZZLE_TYPE_VARCHAR
 
5312
        && key_part->length < field->pack_length()
 
5313
        - ((Field_varstring*)field)->length_bytes)) {
 
5314
 
 
5315
      prefix_len = key_part->length;
 
5316
 
 
5317
      if (col_type == DATA_INT
 
5318
        || col_type == DATA_FLOAT
 
5319
        || col_type == DATA_DOUBLE
 
5320
        || col_type == DATA_DECIMAL) {
 
5321
        errmsg_printf(ERRMSG_LVL_ERROR, 
 
5322
          "MySQL is trying to create a column "
 
5323
          "prefix index field, on an "
 
5324
          "inappropriate data type. Table "
 
5325
          "name %s, column name %s.",
 
5326
          table_name,
 
5327
          key_part->field->field_name);
 
5328
 
 
5329
        prefix_len = 0;
 
5330
      }
 
5331
    } else {
 
5332
      prefix_len = 0;
 
5333
    }
 
5334
 
 
5335
    field_lengths[i] = key_part->length;
 
5336
 
 
5337
    dict_mem_index_add_field(index,
 
5338
      (char*) key_part->field->field_name, prefix_len);
 
5339
  }
 
5340
 
 
5341
  /* Even though we've defined max_supported_key_part_length, we
 
5342
  still do our own checking using field_lengths to be absolutely
 
5343
  sure we don't create too long indexes. */
 
5344
  error = row_create_index_for_mysql(index, trx, field_lengths);
 
5345
 
 
5346
  error = convert_error_code_to_mysql(error, flags, NULL);
 
5347
 
 
5348
  free(field_lengths);
 
5349
 
 
5350
  return(error);
5351
5351
}
5352
5352
 
5353
5353
/*****************************************************************//**
5357
5357
int
5358
5358
create_clustered_index_when_no_primary(
5359
5359
/*===================================*/
5360
 
        trx_t*          trx,            /*!< in: InnoDB transaction handle */
5361
 
        ulint           flags,          /*!< in: InnoDB table flags */
5362
 
        const char*     table_name)     /*!< in: table name */
 
5360
  trx_t*    trx,    /*!< in: InnoDB transaction handle */
 
5361
  ulint   flags,    /*!< in: InnoDB table flags */
 
5362
  const char* table_name) /*!< in: table name */
5363
5363
{
5364
 
        dict_index_t*   index;
5365
 
        int             error;
5366
 
 
5367
 
        /* We pass 0 as the space id, and determine at a lower level the space
5368
 
        id where to store the table */
5369
 
 
5370
 
        index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX",
5371
 
                                      0, DICT_CLUSTERED, 0);
5372
 
 
5373
 
        error = row_create_index_for_mysql(index, trx, NULL);
5374
 
 
5375
 
        error = convert_error_code_to_mysql(error, flags, NULL);
5376
 
 
5377
 
        return(error);
 
5364
  dict_index_t* index;
 
5365
  int   error;
 
5366
 
 
5367
  /* We pass 0 as the space id, and determine at a lower level the space
 
5368
  id where to store the table */
 
5369
 
 
5370
  index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX",
 
5371
              0, DICT_CLUSTERED, 0);
 
5372
 
 
5373
  error = row_create_index_for_mysql(index, trx, NULL);
 
5374
 
 
5375
  error = convert_error_code_to_mysql(error, flags, NULL);
 
5376
 
 
5377
  return(error);
5378
5378
}
5379
5379
 
5380
5380
/*****************************************************************//**
5382
5382
in future. For now, it checks two specifiers:
5383
5383
KEY_BLOCK_SIZE and ROW_FORMAT
5384
5384
If innodb_strict_mode is not set then this function is a no-op
5385
 
@return TRUE if valid. */
 
5385
@return TRUE if valid. */
5386
5386
static
5387
5387
ibool
5388
5388
create_options_are_valid(
5389
5389
/*=====================*/
5390
 
        Session*        session,        /*!< in: connection thread. */
5391
 
        Table&          form,           /*!< in: information on table
5392
 
                                        columns and indexes */
 
5390
  Session*  session,  /*!< in: connection thread. */
 
5391
  Table&    form,   /*!< in: information on table
 
5392
          columns and indexes */
5393
5393
        message::Table& create_proto)
5394
5394
{
5395
 
        ibool   kbs_specified   = FALSE;
5396
 
        ibool   ret             = TRUE;
5397
 
 
5398
 
 
5399
 
        ut_ad(session != NULL);
5400
 
 
5401
 
        /* If innodb_strict_mode is not set don't do any validation. */
5402
 
        if (!(SessionVAR(session, strict_mode))) {
5403
 
                return(TRUE);
5404
 
        }
5405
 
 
5406
 
        /* First check if KEY_BLOCK_SIZE was specified. */
5407
 
        if (create_proto.options().has_key_block_size()) {
5408
 
 
5409
 
                kbs_specified = TRUE;
5410
 
                switch (create_proto.options().key_block_size()) {
5411
 
                case 1:
5412
 
                case 2:
5413
 
                case 4:
5414
 
                case 8:
5415
 
                case 16:
5416
 
                        /* Valid value. */
5417
 
                        break;
5418
 
                default:
5419
 
                        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5420
 
                                            ER_ILLEGAL_HA_CREATE_OPTION,
5421
 
                                            "InnoDB: invalid"
5422
 
                                            " KEY_BLOCK_SIZE = %lu."
5423
 
                                            " Valid values are"
5424
 
                                            " [1, 2, 4, 8, 16]",
5425
 
                                            create_proto.options().key_block_size());
5426
 
                        ret = FALSE;
5427
 
                }
5428
 
        }
5429
 
        
5430
 
        /* If KEY_BLOCK_SIZE was specified, check for its
5431
 
        dependencies. */
5432
 
        if (kbs_specified && !srv_file_per_table) {
5433
 
                push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5434
 
                             ER_ILLEGAL_HA_CREATE_OPTION,
5435
 
                             "InnoDB: KEY_BLOCK_SIZE"
5436
 
                             " requires innodb_file_per_table.");
5437
 
                ret = FALSE;
5438
 
        }
5439
 
 
5440
 
        if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) {
5441
 
                push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5442
 
                             ER_ILLEGAL_HA_CREATE_OPTION,
5443
 
                             "InnoDB: KEY_BLOCK_SIZE"
5444
 
                             " requires innodb_file_format >"
5445
 
                             " Antelope.");
5446
 
                ret = FALSE;
5447
 
        }
5448
 
 
5449
 
        /* Now check for ROW_FORMAT specifier. */
5450
 
        if (create_proto.options().has_row_type()) {
5451
 
                switch (form.s->row_type) {
5452
 
                        const char* row_format_name;
5453
 
                case ROW_TYPE_COMPRESSED:
5454
 
                case ROW_TYPE_DYNAMIC:
5455
 
                        row_format_name
5456
 
                                = form.s->row_type == ROW_TYPE_COMPRESSED
5457
 
                                ? "COMPRESSED"
5458
 
                                : "DYNAMIC";
5459
 
 
5460
 
                        /* These two ROW_FORMATs require
5461
 
                        srv_file_per_table and srv_file_format */
5462
 
                        if (!srv_file_per_table) {
5463
 
                                push_warning_printf(
5464
 
                                        session,
5465
 
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5466
 
                                        ER_ILLEGAL_HA_CREATE_OPTION,
5467
 
                                        "InnoDB: ROW_FORMAT=%s"
5468
 
                                        " requires innodb_file_per_table.",
5469
 
                                        row_format_name);
5470
 
                                        ret = FALSE;
5471
 
 
5472
 
                        }
5473
 
 
5474
 
                        if (srv_file_format < DICT_TF_FORMAT_ZIP) {
5475
 
                                push_warning_printf(
5476
 
                                        session,
5477
 
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5478
 
                                        ER_ILLEGAL_HA_CREATE_OPTION,
5479
 
                                        "InnoDB: ROW_FORMAT=%s"
5480
 
                                        " requires innodb_file_format >"
5481
 
                                        " Antelope.",
5482
 
                                        row_format_name);
5483
 
                                        ret = FALSE;
5484
 
                        }
5485
 
 
5486
 
                        /* Cannot specify KEY_BLOCK_SIZE with
5487
 
                        ROW_FORMAT = DYNAMIC.
5488
 
                        However, we do allow COMPRESSED to be
5489
 
                        specified with KEY_BLOCK_SIZE. */
5490
 
                        if (kbs_specified
5491
 
                            && form.s->row_type == ROW_TYPE_DYNAMIC) {
5492
 
                                push_warning_printf(
5493
 
                                        session,
5494
 
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5495
 
                                        ER_ILLEGAL_HA_CREATE_OPTION,
5496
 
                                        "InnoDB: cannot specify"
5497
 
                                        " ROW_FORMAT = DYNAMIC with"
5498
 
                                        " KEY_BLOCK_SIZE.");
5499
 
                                        ret = FALSE;
5500
 
                        }
5501
 
 
5502
 
                        break;
5503
 
 
5504
 
                case ROW_TYPE_REDUNDANT:
5505
 
                case ROW_TYPE_COMPACT:
5506
 
                case ROW_TYPE_DEFAULT:
5507
 
                        /* Default is COMPACT. */
5508
 
                        row_format_name
5509
 
                                = form.s->row_type == ROW_TYPE_REDUNDANT
5510
 
                                ? "REDUNDANT"
5511
 
                                : "COMPACT";
5512
 
 
5513
 
                        /* Cannot specify KEY_BLOCK_SIZE with these
5514
 
                        format specifiers. */
5515
 
                        if (kbs_specified) {
5516
 
                                push_warning_printf(
5517
 
                                        session,
5518
 
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5519
 
                                        ER_ILLEGAL_HA_CREATE_OPTION,
5520
 
                                        "InnoDB: cannot specify"
5521
 
                                        " ROW_FORMAT = %s with"
5522
 
                                        " KEY_BLOCK_SIZE.",
5523
 
                                        row_format_name);
5524
 
                                        ret = FALSE;
5525
 
                        }
5526
 
 
5527
 
                        break;
5528
 
 
5529
 
                default:
5530
 
                        push_warning(session,
5531
 
                                     DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5532
 
                                     ER_ILLEGAL_HA_CREATE_OPTION,
5533
 
                                     "InnoDB: invalid ROW_FORMAT specifier.");
5534
 
                        ret = FALSE;
5535
 
 
5536
 
                }
5537
 
        }
5538
 
 
5539
 
        return(ret);
 
5395
  ibool kbs_specified = FALSE;
 
5396
  ibool ret   = TRUE;
 
5397
 
 
5398
 
 
5399
  ut_ad(session != NULL);
 
5400
 
 
5401
  /* If innodb_strict_mode is not set don't do any validation. */
 
5402
  if (!(SessionVAR(session, strict_mode))) {
 
5403
    return(TRUE);
 
5404
  }
 
5405
 
 
5406
  /* First check if KEY_BLOCK_SIZE was specified. */
 
5407
  if (create_proto.options().has_key_block_size()) {
 
5408
 
 
5409
    kbs_specified = TRUE;
 
5410
    switch (create_proto.options().key_block_size()) {
 
5411
    case 1:
 
5412
    case 2:
 
5413
    case 4:
 
5414
    case 8:
 
5415
    case 16:
 
5416
      /* Valid value. */
 
5417
      break;
 
5418
    default:
 
5419
      push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5420
              ER_ILLEGAL_HA_CREATE_OPTION,
 
5421
              "InnoDB: invalid"
 
5422
              " KEY_BLOCK_SIZE = %lu."
 
5423
              " Valid values are"
 
5424
              " [1, 2, 4, 8, 16]",
 
5425
              create_proto.options().key_block_size());
 
5426
      ret = FALSE;
 
5427
    }
 
5428
  }
 
5429
  
 
5430
  /* If KEY_BLOCK_SIZE was specified, check for its
 
5431
  dependencies. */
 
5432
  if (kbs_specified && !srv_file_per_table) {
 
5433
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5434
           ER_ILLEGAL_HA_CREATE_OPTION,
 
5435
           "InnoDB: KEY_BLOCK_SIZE"
 
5436
           " requires innodb_file_per_table.");
 
5437
    ret = FALSE;
 
5438
  }
 
5439
 
 
5440
  if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) {
 
5441
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5442
           ER_ILLEGAL_HA_CREATE_OPTION,
 
5443
           "InnoDB: KEY_BLOCK_SIZE"
 
5444
           " requires innodb_file_format >"
 
5445
           " Antelope.");
 
5446
    ret = FALSE;
 
5447
  }
 
5448
 
 
5449
  /* Now check for ROW_FORMAT specifier. */
 
5450
  if (create_proto.options().has_row_type()) {
 
5451
    switch (form.s->row_type) {
 
5452
      const char* row_format_name;
 
5453
    case ROW_TYPE_COMPRESSED:
 
5454
    case ROW_TYPE_DYNAMIC:
 
5455
      row_format_name
 
5456
        = form.s->row_type == ROW_TYPE_COMPRESSED
 
5457
        ? "COMPRESSED"
 
5458
        : "DYNAMIC";
 
5459
 
 
5460
      /* These two ROW_FORMATs require
 
5461
      srv_file_per_table and srv_file_format */
 
5462
      if (!srv_file_per_table) {
 
5463
        push_warning_printf(
 
5464
          session,
 
5465
          DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5466
          ER_ILLEGAL_HA_CREATE_OPTION,
 
5467
          "InnoDB: ROW_FORMAT=%s"
 
5468
          " requires innodb_file_per_table.",
 
5469
          row_format_name);
 
5470
          ret = FALSE;
 
5471
 
 
5472
      }
 
5473
 
 
5474
      if (srv_file_format < DICT_TF_FORMAT_ZIP) {
 
5475
        push_warning_printf(
 
5476
          session,
 
5477
          DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5478
          ER_ILLEGAL_HA_CREATE_OPTION,
 
5479
          "InnoDB: ROW_FORMAT=%s"
 
5480
          " requires innodb_file_format >"
 
5481
          " Antelope.",
 
5482
          row_format_name);
 
5483
          ret = FALSE;
 
5484
      }
 
5485
 
 
5486
      /* Cannot specify KEY_BLOCK_SIZE with
 
5487
      ROW_FORMAT = DYNAMIC.
 
5488
      However, we do allow COMPRESSED to be
 
5489
      specified with KEY_BLOCK_SIZE. */
 
5490
      if (kbs_specified
 
5491
          && form.s->row_type == ROW_TYPE_DYNAMIC) {
 
5492
        push_warning_printf(
 
5493
          session,
 
5494
          DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5495
          ER_ILLEGAL_HA_CREATE_OPTION,
 
5496
          "InnoDB: cannot specify"
 
5497
          " ROW_FORMAT = DYNAMIC with"
 
5498
          " KEY_BLOCK_SIZE.");
 
5499
          ret = FALSE;
 
5500
      }
 
5501
 
 
5502
      break;
 
5503
 
 
5504
    case ROW_TYPE_REDUNDANT:
 
5505
    case ROW_TYPE_COMPACT:
 
5506
    case ROW_TYPE_DEFAULT:
 
5507
      /* Default is COMPACT. */
 
5508
      row_format_name
 
5509
        = form.s->row_type == ROW_TYPE_REDUNDANT
 
5510
        ? "REDUNDANT"
 
5511
        : "COMPACT";
 
5512
 
 
5513
      /* Cannot specify KEY_BLOCK_SIZE with these
 
5514
      format specifiers. */
 
5515
      if (kbs_specified) {
 
5516
        push_warning_printf(
 
5517
          session,
 
5518
          DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5519
          ER_ILLEGAL_HA_CREATE_OPTION,
 
5520
          "InnoDB: cannot specify"
 
5521
          " ROW_FORMAT = %s with"
 
5522
          " KEY_BLOCK_SIZE.",
 
5523
          row_format_name);
 
5524
          ret = FALSE;
 
5525
      }
 
5526
 
 
5527
      break;
 
5528
 
 
5529
    default:
 
5530
      push_warning(session,
 
5531
             DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5532
             ER_ILLEGAL_HA_CREATE_OPTION,
 
5533
             "InnoDB: invalid ROW_FORMAT specifier.");
 
5534
      ret = FALSE;
 
5535
 
 
5536
    }
 
5537
  }
 
5538
 
 
5539
  return(ret);
5540
5540
}
5541
5541
 
5542
5542
/*********************************************************************
5545
5545
int
5546
5546
InnobaseEngine::doCreateTable(
5547
5547
/*================*/
5548
 
        Session         &session,       /*!< in: Session */
5549
 
        Table&          form,           /*!< in: information on table columns and indexes */
 
5548
  Session         &session, /*!< in: Session */
 
5549
  Table&    form,   /*!< in: information on table columns and indexes */
5550
5550
        drizzled::TableIdentifier &identifier,
5551
5551
        message::Table& create_proto)
5552
5552
{
5553
 
        int             error;
5554
 
        dict_table_t*   innobase_table;
5555
 
        trx_t*          parent_trx;
5556
 
        trx_t*          trx;
5557
 
        int             primary_key_no;
5558
 
        uint            i;
5559
 
        char            name2[FN_REFLEN];
5560
 
        char            norm_name[FN_REFLEN];
5561
 
        ib_int64_t      auto_inc_value;
5562
 
        ulint           iflags;
5563
 
        /* Cache the value of innodb_file_format, in case it is
5564
 
        modified by another thread while the table is being created. */
5565
 
        const ulint     file_format = srv_file_format;
 
5553
  int   error;
 
5554
  dict_table_t* innobase_table;
 
5555
  trx_t*    parent_trx;
 
5556
  trx_t*    trx;
 
5557
  int   primary_key_no;
 
5558
  uint    i;
 
5559
  char    name2[FN_REFLEN];
 
5560
  char    norm_name[FN_REFLEN];
 
5561
  ib_int64_t  auto_inc_value;
 
5562
  ulint   iflags;
 
5563
  /* Cache the value of innodb_file_format, in case it is
 
5564
  modified by another thread while the table is being created. */
 
5565
  const ulint file_format = srv_file_format;
5566
5566
        bool lex_identified_temp_table= (create_proto.type() == message::Table::TEMPORARY);
5567
5567
 
5568
 
        const char *table_name= identifier.getPath().c_str();
 
5568
  const char *table_name= identifier.getPath().c_str();
5569
5569
 
5570
5570
#ifdef __WIN__
5571
 
        /* Names passed in from server are in two formats:
5572
 
        1. <database_name>/<table_name>: for normal table creation
5573
 
        2. full path: for temp table creation, or sym link
5574
 
 
5575
 
        When srv_file_per_table is on, check for full path pattern, i.e.
5576
 
        X:\dir\...,             X is a driver letter, or
5577
 
        \\dir1\dir2\...,        UNC path
5578
 
        returns error if it is in full path format, but not creating a temp.
5579
 
        table. Currently InnoDB does not support symbolic link on Windows. */
5580
 
 
5581
 
        if (srv_file_per_table
5582
 
            && (! lex_identified_temp_table)) {
5583
 
 
5584
 
                if ((table_name[1] == ':')
5585
 
                    || (table_name[0] == '\\' && table_name[1] == '\\')) {
5586
 
                        errmsg_printf(ERRMSG_LVL_ERROR, "Cannot create table %s\n", table_name);
5587
 
                        return(HA_ERR_GENERIC);
5588
 
                }
5589
 
        }
 
5571
  /* Names passed in from server are in two formats:
 
5572
  1. <database_name>/<table_name>: for normal table creation
 
5573
  2. full path: for temp table creation, or sym link
 
5574
 
 
5575
  When srv_file_per_table is on, check for full path pattern, i.e.
 
5576
  X:\dir\...,   X is a driver letter, or
 
5577
  \\dir1\dir2\...,  UNC path
 
5578
  returns error if it is in full path format, but not creating a temp.
 
5579
  table. Currently InnoDB does not support symbolic link on Windows. */
 
5580
 
 
5581
  if (srv_file_per_table
 
5582
      && (! lex_identified_temp_table)) {
 
5583
 
 
5584
    if ((table_name[1] == ':')
 
5585
        || (table_name[0] == '\\' && table_name[1] == '\\')) {
 
5586
      errmsg_printf(ERRMSG_LVL_ERROR, "Cannot create table %s\n", table_name);
 
5587
      return(HA_ERR_GENERIC);
 
5588
    }
 
5589
  }
5590
5590
#endif
5591
5591
 
5592
 
        if (form.s->fields > 1000) {
5593
 
                /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
5594
 
                but we play safe here */
5595
 
 
5596
 
                return(HA_ERR_TO_BIG_ROW);
5597
 
        }
5598
 
 
5599
 
        /* Get the transaction associated with the current session, or create one
5600
 
        if not yet created */
5601
 
 
5602
 
        parent_trx = check_trx_exists(&session);
5603
 
 
5604
 
        /* In case MySQL calls this in the middle of a SELECT query, release
5605
 
        possible adaptive hash latch to avoid deadlocks of threads */
5606
 
 
5607
 
        trx_search_latch_release_if_reserved(parent_trx);
5608
 
 
5609
 
        trx = innobase_trx_allocate(&session);
5610
 
 
5611
 
        srv_lower_case_table_names = TRUE;
5612
 
 
5613
 
        strcpy(name2, table_name);
5614
 
 
5615
 
        normalize_table_name(norm_name, name2);
5616
 
 
5617
 
        /* Latch the InnoDB data dictionary exclusively so that no deadlocks
5618
 
        or lock waits can happen in it during a table create operation.
5619
 
        Drop table etc. do this latching in row0mysql.c. */
5620
 
 
5621
 
        row_mysql_lock_data_dictionary(trx);
5622
 
 
5623
 
        /* Create the table definition in InnoDB */
5624
 
 
5625
 
        iflags = 0;
5626
 
 
5627
 
        /* Validate create options if innodb_strict_mode is set. */
5628
 
        if (! create_options_are_valid(&session, form, create_proto)) {
5629
 
                error = ER_ILLEGAL_HA_CREATE_OPTION;
5630
 
                goto cleanup;
5631
 
        }
5632
 
 
5633
 
        if (create_proto.options().has_key_block_size()) {
5634
 
                /* Determine the page_zip.ssize corresponding to the
5635
 
                requested page size (key_block_size) in kilobytes. */
5636
 
 
5637
 
                ulint   ssize, ksize;
5638
 
                ulint   key_block_size = create_proto.options().key_block_size();
5639
 
 
5640
 
                for (ssize = ksize = 1; ssize <= DICT_TF_ZSSIZE_MAX;
5641
 
                     ssize++, ksize <<= 1) {
5642
 
                        if (key_block_size == ksize) {
5643
 
                                iflags = ssize << DICT_TF_ZSSIZE_SHIFT
5644
 
                                        | DICT_TF_COMPACT
5645
 
                                        | DICT_TF_FORMAT_ZIP
5646
 
                                          << DICT_TF_FORMAT_SHIFT;
5647
 
                                break;
5648
 
                        }
5649
 
                }
5650
 
 
5651
 
                if (!srv_file_per_table) {
5652
 
                        push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5653
 
                                     ER_ILLEGAL_HA_CREATE_OPTION,
5654
 
                                     "InnoDB: KEY_BLOCK_SIZE"
5655
 
                                     " requires innodb_file_per_table.");
5656
 
                        iflags = 0;
5657
 
                }
5658
 
 
5659
 
                if (file_format < DICT_TF_FORMAT_ZIP) {
5660
 
                        push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5661
 
                                     ER_ILLEGAL_HA_CREATE_OPTION,
5662
 
                                     "InnoDB: KEY_BLOCK_SIZE"
5663
 
                                     " requires innodb_file_format >"
5664
 
                                     " Antelope.");
5665
 
                        iflags = 0;
5666
 
                }
5667
 
 
5668
 
                if (!iflags) {
5669
 
                        push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
5670
 
                                            ER_ILLEGAL_HA_CREATE_OPTION,
5671
 
                                            "InnoDB: ignoring"
5672
 
                                            " KEY_BLOCK_SIZE=%lu.",
5673
 
                                            create_proto.options().key_block_size());
5674
 
                }
5675
 
        }
5676
 
 
5677
 
        if (create_proto.options().has_row_type()) {
5678
 
                if (iflags) {
5679
 
                        /* KEY_BLOCK_SIZE was specified. */
5680
 
                        if (form.s->row_type != ROW_TYPE_COMPRESSED) {
5681
 
                                /* ROW_FORMAT other than COMPRESSED
5682
 
                                ignores KEY_BLOCK_SIZE.  It does not
5683
 
                                make sense to reject conflicting
5684
 
                                KEY_BLOCK_SIZE and ROW_FORMAT, because
5685
 
                                such combinations can be obtained
5686
 
                                with ALTER TABLE anyway. */
5687
 
                                push_warning_printf(
5688
 
                                        &session,
5689
 
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
5690
 
                                        ER_ILLEGAL_HA_CREATE_OPTION,
5691
 
                                        "InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
5692
 
                                        " unless ROW_FORMAT=COMPRESSED.",
5693
 
                                        create_proto.options().key_block_size());
5694
 
                                iflags = 0;
5695
 
                        }
5696
 
                } else {
5697
 
                        /* No KEY_BLOCK_SIZE */
5698
 
                        if (form.s->row_type == ROW_TYPE_COMPRESSED) {
5699
 
                                /* ROW_FORMAT=COMPRESSED without
5700
 
                                KEY_BLOCK_SIZE implies half the
5701
 
                                maximum KEY_BLOCK_SIZE. */
5702
 
                                iflags = (DICT_TF_ZSSIZE_MAX - 1)
5703
 
                                        << DICT_TF_ZSSIZE_SHIFT
5704
 
                                        | DICT_TF_COMPACT
5705
 
                                        | DICT_TF_FORMAT_ZIP
5706
 
                                        << DICT_TF_FORMAT_SHIFT;
 
5592
  if (form.s->fields > 1000) {
 
5593
    /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
 
5594
    but we play safe here */
 
5595
 
 
5596
    return(HA_ERR_TO_BIG_ROW);
 
5597
  }
 
5598
 
 
5599
  /* Get the transaction associated with the current session, or create one
 
5600
  if not yet created */
 
5601
 
 
5602
  parent_trx = check_trx_exists(&session);
 
5603
 
 
5604
  /* In case MySQL calls this in the middle of a SELECT query, release
 
5605
  possible adaptive hash latch to avoid deadlocks of threads */
 
5606
 
 
5607
  trx_search_latch_release_if_reserved(parent_trx);
 
5608
 
 
5609
  trx = innobase_trx_allocate(&session);
 
5610
 
 
5611
  srv_lower_case_table_names = TRUE;
 
5612
 
 
5613
  strcpy(name2, table_name);
 
5614
 
 
5615
  normalize_table_name(norm_name, name2);
 
5616
 
 
5617
  /* Latch the InnoDB data dictionary exclusively so that no deadlocks
 
5618
  or lock waits can happen in it during a table create operation.
 
5619
  Drop table etc. do this latching in row0mysql.c. */
 
5620
 
 
5621
  row_mysql_lock_data_dictionary(trx);
 
5622
 
 
5623
  /* Create the table definition in InnoDB */
 
5624
 
 
5625
  iflags = 0;
 
5626
 
 
5627
  /* Validate create options if innodb_strict_mode is set. */
 
5628
  if (! create_options_are_valid(&session, form, create_proto)) {
 
5629
    error = ER_ILLEGAL_HA_CREATE_OPTION;
 
5630
    goto cleanup;
 
5631
  }
 
5632
 
 
5633
  if (create_proto.options().has_key_block_size()) {
 
5634
    /* Determine the page_zip.ssize corresponding to the
 
5635
    requested page size (key_block_size) in kilobytes. */
 
5636
 
 
5637
    ulint ssize, ksize;
 
5638
    ulint key_block_size = create_proto.options().key_block_size();
 
5639
 
 
5640
    for (ssize = ksize = 1; ssize <= DICT_TF_ZSSIZE_MAX;
 
5641
         ssize++, ksize <<= 1) {
 
5642
      if (key_block_size == ksize) {
 
5643
        iflags = ssize << DICT_TF_ZSSIZE_SHIFT
 
5644
          | DICT_TF_COMPACT
 
5645
          | DICT_TF_FORMAT_ZIP
 
5646
            << DICT_TF_FORMAT_SHIFT;
 
5647
        break;
 
5648
      }
 
5649
    }
 
5650
 
 
5651
    if (!srv_file_per_table) {
 
5652
      push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5653
             ER_ILLEGAL_HA_CREATE_OPTION,
 
5654
             "InnoDB: KEY_BLOCK_SIZE"
 
5655
             " requires innodb_file_per_table.");
 
5656
      iflags = 0;
 
5657
    }
 
5658
 
 
5659
    if (file_format < DICT_TF_FORMAT_ZIP) {
 
5660
      push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5661
             ER_ILLEGAL_HA_CREATE_OPTION,
 
5662
             "InnoDB: KEY_BLOCK_SIZE"
 
5663
             " requires innodb_file_format >"
 
5664
             " Antelope.");
 
5665
      iflags = 0;
 
5666
    }
 
5667
 
 
5668
    if (!iflags) {
 
5669
      push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5670
              ER_ILLEGAL_HA_CREATE_OPTION,
 
5671
              "InnoDB: ignoring"
 
5672
              " KEY_BLOCK_SIZE=%lu.",
 
5673
              create_proto.options().key_block_size());
 
5674
    }
 
5675
  }
 
5676
 
 
5677
  if (create_proto.options().has_row_type()) {
 
5678
    if (iflags) {
 
5679
      /* KEY_BLOCK_SIZE was specified. */
 
5680
      if (form.s->row_type != ROW_TYPE_COMPRESSED) {
 
5681
        /* ROW_FORMAT other than COMPRESSED
 
5682
        ignores KEY_BLOCK_SIZE.  It does not
 
5683
        make sense to reject conflicting
 
5684
        KEY_BLOCK_SIZE and ROW_FORMAT, because
 
5685
        such combinations can be obtained
 
5686
        with ALTER TABLE anyway. */
 
5687
        push_warning_printf(
 
5688
          &session,
 
5689
          DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5690
          ER_ILLEGAL_HA_CREATE_OPTION,
 
5691
          "InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
 
5692
          " unless ROW_FORMAT=COMPRESSED.",
 
5693
          create_proto.options().key_block_size());
 
5694
        iflags = 0;
 
5695
      }
 
5696
    } else {
 
5697
      /* No KEY_BLOCK_SIZE */
 
5698
      if (form.s->row_type == ROW_TYPE_COMPRESSED) {
 
5699
        /* ROW_FORMAT=COMPRESSED without
 
5700
        KEY_BLOCK_SIZE implies half the
 
5701
        maximum KEY_BLOCK_SIZE. */
 
5702
        iflags = (DICT_TF_ZSSIZE_MAX - 1)
 
5703
          << DICT_TF_ZSSIZE_SHIFT
 
5704
          | DICT_TF_COMPACT
 
5705
          | DICT_TF_FORMAT_ZIP
 
5706
          << DICT_TF_FORMAT_SHIFT;
5707
5707
#if DICT_TF_ZSSIZE_MAX < 1
5708
5708
# error "DICT_TF_ZSSIZE_MAX < 1"
5709
5709
#endif
5710
 
                        }
5711
 
                }
5712
 
 
5713
 
                switch (form.s->row_type) {
5714
 
                        const char* row_format_name;
5715
 
                case ROW_TYPE_REDUNDANT:
5716
 
                        break;
5717
 
                case ROW_TYPE_COMPRESSED:
5718
 
                case ROW_TYPE_DYNAMIC:
5719
 
                        row_format_name
5720
 
                                = form.s->row_type == ROW_TYPE_COMPRESSED
5721
 
                                ? "COMPRESSED"
5722
 
                                : "DYNAMIC";
5723
 
 
5724
 
                        if (!srv_file_per_table) {
5725
 
                                push_warning_printf(
5726
 
                                        &session,
5727
 
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
5728
 
                                        ER_ILLEGAL_HA_CREATE_OPTION,
5729
 
                                        "InnoDB: ROW_FORMAT=%s"
5730
 
                                        " requires innodb_file_per_table.",
5731
 
                                        row_format_name);
5732
 
                        } else if (file_format < DICT_TF_FORMAT_ZIP) {
5733
 
                                push_warning_printf(
5734
 
                                        &session,
5735
 
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
5736
 
                                        ER_ILLEGAL_HA_CREATE_OPTION,
5737
 
                                        "InnoDB: ROW_FORMAT=%s"
5738
 
                                        " requires innodb_file_format >"
5739
 
                                        " Antelope.",
5740
 
                                        row_format_name);
5741
 
                        } else {
5742
 
                                iflags |= DICT_TF_COMPACT
5743
 
                                        | (DICT_TF_FORMAT_ZIP
5744
 
                                           << DICT_TF_FORMAT_SHIFT);
5745
 
                                break;
5746
 
                        }
5747
 
 
5748
 
                        /* fall through */
5749
 
                case ROW_TYPE_NOT_USED:
5750
 
                case ROW_TYPE_FIXED:
5751
 
                default:
 
5710
      }
 
5711
    }
 
5712
 
 
5713
    switch (form.s->row_type) {
 
5714
      const char* row_format_name;
 
5715
    case ROW_TYPE_REDUNDANT:
 
5716
      break;
 
5717
    case ROW_TYPE_COMPRESSED:
 
5718
    case ROW_TYPE_DYNAMIC:
 
5719
      row_format_name
 
5720
        = form.s->row_type == ROW_TYPE_COMPRESSED
 
5721
        ? "COMPRESSED"
 
5722
        : "DYNAMIC";
 
5723
 
 
5724
      if (!srv_file_per_table) {
 
5725
        push_warning_printf(
 
5726
          &session,
 
5727
          DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5728
          ER_ILLEGAL_HA_CREATE_OPTION,
 
5729
          "InnoDB: ROW_FORMAT=%s"
 
5730
          " requires innodb_file_per_table.",
 
5731
          row_format_name);
 
5732
      } else if (file_format < DICT_TF_FORMAT_ZIP) {
 
5733
        push_warning_printf(
 
5734
          &session,
 
5735
          DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5736
          ER_ILLEGAL_HA_CREATE_OPTION,
 
5737
          "InnoDB: ROW_FORMAT=%s"
 
5738
          " requires innodb_file_format >"
 
5739
          " Antelope.",
 
5740
          row_format_name);
 
5741
      } else {
 
5742
        iflags |= DICT_TF_COMPACT
 
5743
          | (DICT_TF_FORMAT_ZIP
 
5744
             << DICT_TF_FORMAT_SHIFT);
 
5745
        break;
 
5746
      }
 
5747
 
 
5748
      /* fall through */
 
5749
    case ROW_TYPE_NOT_USED:
 
5750
    case ROW_TYPE_FIXED:
 
5751
    default:
5752
5752
                        error = ER_ILLEGAL_HA_CREATE_OPTION;
5753
5753
                        goto cleanup;
5754
 
                case ROW_TYPE_DEFAULT:
5755
 
                case ROW_TYPE_COMPACT:
5756
 
                        iflags = DICT_TF_COMPACT;
5757
 
                        break;
5758
 
                }
5759
 
        } else if (!iflags) {
5760
 
                /* No KEY_BLOCK_SIZE or ROW_FORMAT specified:
5761
 
                use ROW_FORMAT=COMPACT by default. */
5762
 
                iflags = DICT_TF_COMPACT;
5763
 
        }
5764
 
 
5765
 
        error = create_table_def(trx, &form, norm_name,
5766
 
                lex_identified_temp_table ? name2 : NULL,
5767
 
                iflags);
5768
 
 
5769
 
        if (error) {
5770
 
                goto cleanup;
5771
 
        }
5772
 
 
5773
 
        /* Look for a primary key */
5774
 
 
5775
 
        primary_key_no= (form.s->primary_key != MAX_KEY ?
5776
 
                         (int) form.s->primary_key :
5777
 
                         -1);
5778
 
 
5779
 
        /* Our function row_get_mysql_key_number_for_index assumes
5780
 
        the primary key is always number 0, if it exists */
5781
 
 
5782
 
        assert(primary_key_no == -1 || primary_key_no == 0);
5783
 
 
5784
 
        /* Create the keys */
5785
 
 
5786
 
        if (form.s->keys == 0 || primary_key_no == -1) {
5787
 
                /* Create an index which is used as the clustered index;
5788
 
                order the rows by their row id which is internally generated
5789
 
                by InnoDB */
5790
 
 
5791
 
                error = create_clustered_index_when_no_primary(
5792
 
                        trx, iflags, norm_name);
5793
 
                if (error) {
5794
 
                        goto cleanup;
5795
 
                }
5796
 
        }
5797
 
 
5798
 
        if (primary_key_no != -1) {
5799
 
                /* In InnoDB the clustered index must always be created
5800
 
                first */
5801
 
                if ((error = create_index(trx, &form, iflags, norm_name,
5802
 
                                          (uint) primary_key_no))) {
5803
 
                        goto cleanup;
5804
 
                }
5805
 
        }
5806
 
 
5807
 
        for (i = 0; i < form.s->keys; i++) {
5808
 
 
5809
 
                if (i != (uint) primary_key_no) {
5810
 
 
5811
 
                        if ((error = create_index(trx, &form, iflags, norm_name,
5812
 
                                                  i))) {
5813
 
                                goto cleanup;
5814
 
                        }
5815
 
                }
5816
 
        }
5817
 
 
5818
 
        if (trx->mysql_query_str) {
5819
 
                error = row_table_add_foreign_constraints(trx,
5820
 
                        trx->mysql_query_str, norm_name,
5821
 
                        lex_identified_temp_table);
5822
 
 
5823
 
                error = convert_error_code_to_mysql(error, iflags, NULL);
5824
 
 
5825
 
                if (error) {
5826
 
                        goto cleanup;
5827
 
                }
5828
 
        }
5829
 
 
5830
 
        innobase_commit_low(trx);
5831
 
 
5832
 
        row_mysql_unlock_data_dictionary(trx);
5833
 
 
5834
 
        /* Flush the log to reduce probability that the .frm files and
5835
 
        the InnoDB data dictionary get out-of-sync if the user runs
5836
 
        with innodb_flush_log_at_trx_commit = 0 */
5837
 
 
5838
 
        log_buffer_flush_to_disk();
5839
 
 
5840
 
        innobase_table = dict_table_get(norm_name, FALSE);
5841
 
 
5842
 
        assert(innobase_table != 0);
5843
 
 
5844
 
        if (innobase_table) {
5845
 
                /* We update the highest file format in the system table
5846
 
                space, if this table has higher file format setting. */
5847
 
 
5848
 
                trx_sys_file_format_max_upgrade(
5849
 
                        (const char**) &innobase_file_format_check,
5850
 
                        dict_table_get_format(innobase_table));
5851
 
        }
5852
 
 
5853
 
        /* Note: We can't call update_session() as prebuilt will not be
5854
 
        setup at this stage and so we use session. */
5855
 
 
5856
 
        /* We need to copy the AUTOINC value from the old table if
5857
 
        this is an ALTER TABLE. */
5858
 
 
5859
 
        if ((create_proto.options().has_auto_increment_value()
5860
 
            || session_sql_command(&session) == SQLCOM_ALTER_TABLE)
5861
 
            && create_proto.options().auto_increment_value() != 0) {
5862
 
 
5863
 
                /* Query was ALTER TABLE...AUTO_INCREMENT = x; or
5864
 
                CREATE TABLE ...AUTO_INCREMENT = x; Find out a table
5865
 
                definition from the dictionary and get the current value
5866
 
                of the auto increment field. Set a new value to the
5867
 
                auto increment field if the value is greater than the
5868
 
                maximum value in the column. */
5869
 
 
5870
 
                auto_inc_value = create_proto.options().auto_increment_value();
5871
 
 
5872
 
                dict_table_autoinc_lock(innobase_table);
5873
 
                dict_table_autoinc_initialize(innobase_table, auto_inc_value);
5874
 
                dict_table_autoinc_unlock(innobase_table);
5875
 
        }
5876
 
 
5877
 
        /* Tell the InnoDB server that there might be work for
5878
 
        utility threads: */
5879
 
 
5880
 
        srv_active_wake_master_thread();
5881
 
 
5882
 
        trx_free_for_mysql(trx);
 
5754
    case ROW_TYPE_DEFAULT:
 
5755
    case ROW_TYPE_COMPACT:
 
5756
      iflags = DICT_TF_COMPACT;
 
5757
      break;
 
5758
    }
 
5759
  } else if (!iflags) {
 
5760
    /* No KEY_BLOCK_SIZE or ROW_FORMAT specified:
 
5761
    use ROW_FORMAT=COMPACT by default. */
 
5762
    iflags = DICT_TF_COMPACT;
 
5763
  }
 
5764
 
 
5765
  error = create_table_def(trx, &form, norm_name,
 
5766
    lex_identified_temp_table ? name2 : NULL,
 
5767
    iflags);
 
5768
 
 
5769
  if (error) {
 
5770
    goto cleanup;
 
5771
  }
 
5772
 
 
5773
  /* Look for a primary key */
 
5774
 
 
5775
  primary_key_no= (form.s->primary_key != MAX_KEY ?
 
5776
       (int) form.s->primary_key :
 
5777
       -1);
 
5778
 
 
5779
  /* Our function row_get_mysql_key_number_for_index assumes
 
5780
  the primary key is always number 0, if it exists */
 
5781
 
 
5782
  assert(primary_key_no == -1 || primary_key_no == 0);
 
5783
 
 
5784
  /* Create the keys */
 
5785
 
 
5786
  if (form.s->keys == 0 || primary_key_no == -1) {
 
5787
    /* Create an index which is used as the clustered index;
 
5788
    order the rows by their row id which is internally generated
 
5789
    by InnoDB */
 
5790
 
 
5791
    error = create_clustered_index_when_no_primary(
 
5792
      trx, iflags, norm_name);
 
5793
    if (error) {
 
5794
      goto cleanup;
 
5795
    }
 
5796
  }
 
5797
 
 
5798
  if (primary_key_no != -1) {
 
5799
    /* In InnoDB the clustered index must always be created
 
5800
    first */
 
5801
    if ((error = create_index(trx, &form, iflags, norm_name,
 
5802
            (uint) primary_key_no))) {
 
5803
      goto cleanup;
 
5804
    }
 
5805
  }
 
5806
 
 
5807
  for (i = 0; i < form.s->keys; i++) {
 
5808
 
 
5809
    if (i != (uint) primary_key_no) {
 
5810
 
 
5811
      if ((error = create_index(trx, &form, iflags, norm_name,
 
5812
              i))) {
 
5813
        goto cleanup;
 
5814
      }
 
5815
    }
 
5816
  }
 
5817
 
 
5818
  if (trx->mysql_query_str) {
 
5819
    error = row_table_add_foreign_constraints(trx,
 
5820
      trx->mysql_query_str, norm_name,
 
5821
      lex_identified_temp_table);
 
5822
 
 
5823
    error = convert_error_code_to_mysql(error, iflags, NULL);
 
5824
 
 
5825
    if (error) {
 
5826
      goto cleanup;
 
5827
    }
 
5828
  }
 
5829
 
 
5830
  innobase_commit_low(trx);
 
5831
 
 
5832
  row_mysql_unlock_data_dictionary(trx);
 
5833
 
 
5834
  /* Flush the log to reduce probability that the .frm files and
 
5835
  the InnoDB data dictionary get out-of-sync if the user runs
 
5836
  with innodb_flush_log_at_trx_commit = 0 */
 
5837
 
 
5838
  log_buffer_flush_to_disk();
 
5839
 
 
5840
  innobase_table = dict_table_get(norm_name, FALSE);
 
5841
 
 
5842
  assert(innobase_table != 0);
 
5843
 
 
5844
  if (innobase_table) {
 
5845
    /* We update the highest file format in the system table
 
5846
    space, if this table has higher file format setting. */
 
5847
 
 
5848
    trx_sys_file_format_max_upgrade(
 
5849
      (const char**) &innobase_file_format_check,
 
5850
      dict_table_get_format(innobase_table));
 
5851
  }
 
5852
 
 
5853
  /* Note: We can't call update_session() as prebuilt will not be
 
5854
  setup at this stage and so we use session. */
 
5855
 
 
5856
  /* We need to copy the AUTOINC value from the old table if
 
5857
  this is an ALTER TABLE. */
 
5858
 
 
5859
  if ((create_proto.options().has_auto_increment_value()
 
5860
      || session_sql_command(&session) == SQLCOM_ALTER_TABLE)
 
5861
      && create_proto.options().auto_increment_value() != 0) {
 
5862
 
 
5863
    /* Query was ALTER TABLE...AUTO_INCREMENT = x; or
 
5864
    CREATE TABLE ...AUTO_INCREMENT = x; Find out a table
 
5865
    definition from the dictionary and get the current value
 
5866
    of the auto increment field. Set a new value to the
 
5867
    auto increment field if the value is greater than the
 
5868
    maximum value in the column. */
 
5869
 
 
5870
    auto_inc_value = create_proto.options().auto_increment_value();
 
5871
 
 
5872
    dict_table_autoinc_lock(innobase_table);
 
5873
    dict_table_autoinc_initialize(innobase_table, auto_inc_value);
 
5874
    dict_table_autoinc_unlock(innobase_table);
 
5875
  }
 
5876
 
 
5877
  /* Tell the InnoDB server that there might be work for
 
5878
  utility threads: */
 
5879
 
 
5880
  srv_active_wake_master_thread();
 
5881
 
 
5882
  trx_free_for_mysql(trx);
5883
5883
 
5884
5884
        StorageEngine::writeDefinitionFromPath(identifier, create_proto);
5885
5885
 
5886
 
        return(0);
 
5886
  return(0);
5887
5887
 
5888
5888
cleanup:
5889
 
        innobase_commit_low(trx);
5890
 
 
5891
 
        row_mysql_unlock_data_dictionary(trx);
5892
 
 
5893
 
        trx_free_for_mysql(trx);
5894
 
 
5895
 
        return(error);
 
5889
  innobase_commit_low(trx);
 
5890
 
 
5891
  row_mysql_unlock_data_dictionary(trx);
 
5892
 
 
5893
  trx_free_for_mysql(trx);
 
5894
 
 
5895
  return(error);
5896
5896
}
5897
5897
 
5898
5898
/*****************************************************************//**
5899
5899
Discards or imports an InnoDB tablespace.
5900
 
@return 0 == success, -1 == error */
 
5900
@return 0 == success, -1 == error */
5901
5901
UNIV_INTERN
5902
5902
int
5903
5903
ha_innobase::discard_or_import_tablespace(
5904
5904
/*======================================*/
5905
 
        my_bool discard)        /*!< in: TRUE if discard, else import */
 
5905
  my_bool discard)  /*!< in: TRUE if discard, else import */
5906
5906
{
5907
 
        dict_table_t*   dict_table;
5908
 
        trx_t*          trx;
5909
 
        int             err;
5910
 
 
5911
 
        ut_a(prebuilt->trx);
5912
 
        ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
5913
 
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
5914
 
 
5915
 
        dict_table = prebuilt->table;
5916
 
        trx = prebuilt->trx;
5917
 
 
5918
 
        if (discard) {
5919
 
                err = row_discard_tablespace_for_mysql(dict_table->name, trx);
5920
 
        } else {
5921
 
                err = row_import_tablespace_for_mysql(dict_table->name, trx);
5922
 
        }
5923
 
 
5924
 
        err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
5925
 
 
5926
 
        return(err);
 
5907
  dict_table_t* dict_table;
 
5908
  trx_t*    trx;
 
5909
  int   err;
 
5910
 
 
5911
  ut_a(prebuilt->trx);
 
5912
  ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
 
5913
  ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
5914
 
 
5915
  dict_table = prebuilt->table;
 
5916
  trx = prebuilt->trx;
 
5917
 
 
5918
  if (discard) {
 
5919
    err = row_discard_tablespace_for_mysql(dict_table->name, trx);
 
5920
  } else {
 
5921
    err = row_import_tablespace_for_mysql(dict_table->name, trx);
 
5922
  }
 
5923
 
 
5924
  err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
 
5925
 
 
5926
  return(err);
5927
5927
}
5928
5928
 
5929
5929
/*****************************************************************//**
5930
5930
Deletes all rows of an InnoDB table.
5931
 
@return error number */
 
5931
@return error number */
5932
5932
UNIV_INTERN
5933
5933
int
5934
5934
ha_innobase::delete_all_rows(void)
5935
5935
/*==============================*/
5936
5936
{
5937
 
        int             error;
5938
 
 
5939
 
        /* Get the transaction associated with the current session, or create one
5940
 
        if not yet created, and update prebuilt->trx */
5941
 
 
5942
 
        update_session(ha_session());
5943
 
 
5944
 
        if (session_sql_command(user_session) != SQLCOM_TRUNCATE) {
5945
 
        fallback:
5946
 
                /* We only handle TRUNCATE TABLE t as a special case.
5947
 
                DELETE FROM t will have to use ha_innobase::delete_row(),
5948
 
                because DELETE is transactional while TRUNCATE is not. */
5949
 
                return(errno=HA_ERR_WRONG_COMMAND);
5950
 
        }
5951
 
 
5952
 
        /* Truncate the table in InnoDB */
5953
 
 
5954
 
        error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
5955
 
        if (error == DB_ERROR) {
5956
 
                /* Cannot truncate; resort to ha_innobase::delete_row() */
5957
 
                goto fallback;
5958
 
        }
5959
 
 
5960
 
        error = convert_error_code_to_mysql(error, prebuilt->table->flags,
5961
 
                                            NULL);
5962
 
 
5963
 
        return(error);
 
5937
  int   error;
 
5938
 
 
5939
  /* Get the transaction associated with the current session, or create one
 
5940
  if not yet created, and update prebuilt->trx */
 
5941
 
 
5942
  update_session(ha_session());
 
5943
 
 
5944
  if (session_sql_command(user_session) != SQLCOM_TRUNCATE) {
 
5945
  fallback:
 
5946
    /* We only handle TRUNCATE TABLE t as a special case.
 
5947
    DELETE FROM t will have to use ha_innobase::delete_row(),
 
5948
    because DELETE is transactional while TRUNCATE is not. */
 
5949
    return(errno=HA_ERR_WRONG_COMMAND);
 
5950
  }
 
5951
 
 
5952
  /* Truncate the table in InnoDB */
 
5953
 
 
5954
  error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
 
5955
  if (error == DB_ERROR) {
 
5956
    /* Cannot truncate; resort to ha_innobase::delete_row() */
 
5957
    goto fallback;
 
5958
  }
 
5959
 
 
5960
  error = convert_error_code_to_mysql(error, prebuilt->table->flags,
 
5961
              NULL);
 
5962
 
 
5963
  return(error);
5964
5964
}
5965
5965
 
5966
5966
/*****************************************************************//**
5969
5969
Then the current user cannot have locks set on the table. Drop table
5970
5970
operation inside InnoDB will remove all locks any user has on the table
5971
5971
inside InnoDB.
5972
 
@return error number */
 
5972
@return error number */
5973
5973
UNIV_INTERN
5974
5974
int
5975
5975
InnobaseEngine::doDropTable(
5977
5977
        Session &session,
5978
5978
        TableIdentifier &identifier)
5979
5979
{
5980
 
        int     error;
5981
 
        trx_t*  parent_trx;
5982
 
        trx_t*  trx;
5983
 
        char    norm_name[1000];
5984
 
 
5985
 
        ut_a(identifier.getPath().length() < 1000);
5986
 
 
5987
 
        /* Strangely, MySQL passes the table name without the '.frm'
5988
 
        extension, in contrast to ::create */
5989
 
        normalize_table_name(norm_name, identifier.getPath().c_str());
5990
 
 
5991
 
        /* Get the transaction associated with the current session, or create one
5992
 
        if not yet created */
5993
 
 
5994
 
        parent_trx = check_trx_exists(&session);
5995
 
 
5996
 
        /* In case MySQL calls this in the middle of a SELECT query, release
5997
 
        possible adaptive hash latch to avoid deadlocks of threads */
5998
 
 
5999
 
        trx_search_latch_release_if_reserved(parent_trx);
6000
 
 
6001
 
        trx = innobase_trx_allocate(&session);
6002
 
 
6003
 
        srv_lower_case_table_names = TRUE;
6004
 
 
6005
 
        /* Drop the table in InnoDB */
6006
 
 
6007
 
        error = row_drop_table_for_mysql(norm_name, trx,
6008
 
                                         session_sql_command(&session)
6009
 
                                         == SQLCOM_DROP_DB);
6010
 
 
6011
 
        /* Flush the log to reduce probability that the .frm files and
6012
 
        the InnoDB data dictionary get out-of-sync if the user runs
6013
 
        with innodb_flush_log_at_trx_commit = 0 */
6014
 
 
6015
 
        log_buffer_flush_to_disk();
6016
 
 
6017
 
        /* Tell the InnoDB server that there might be work for
6018
 
        utility threads: */
6019
 
 
6020
 
        srv_active_wake_master_thread();
6021
 
 
6022
 
        innobase_commit_low(trx);
6023
 
 
6024
 
        trx_free_for_mysql(trx);
6025
 
 
6026
 
        if(error!=ENOENT)
6027
 
          error = convert_error_code_to_mysql(error, 0, NULL);
 
5980
  int error;
 
5981
  trx_t*  parent_trx;
 
5982
  trx_t*  trx;
 
5983
  char  norm_name[1000];
 
5984
 
 
5985
  ut_a(identifier.getPath().length() < 1000);
 
5986
 
 
5987
  /* Strangely, MySQL passes the table name without the '.frm'
 
5988
  extension, in contrast to ::create */
 
5989
  normalize_table_name(norm_name, identifier.getPath().c_str());
 
5990
 
 
5991
  /* Get the transaction associated with the current session, or create one
 
5992
  if not yet created */
 
5993
 
 
5994
  parent_trx = check_trx_exists(&session);
 
5995
 
 
5996
  /* In case MySQL calls this in the middle of a SELECT query, release
 
5997
  possible adaptive hash latch to avoid deadlocks of threads */
 
5998
 
 
5999
  trx_search_latch_release_if_reserved(parent_trx);
 
6000
 
 
6001
  trx = innobase_trx_allocate(&session);
 
6002
 
 
6003
  srv_lower_case_table_names = TRUE;
 
6004
 
 
6005
  /* Drop the table in InnoDB */
 
6006
 
 
6007
  error = row_drop_table_for_mysql(norm_name, trx,
 
6008
           session_sql_command(&session)
 
6009
           == SQLCOM_DROP_DB);
 
6010
 
 
6011
  /* Flush the log to reduce probability that the .frm files and
 
6012
  the InnoDB data dictionary get out-of-sync if the user runs
 
6013
  with innodb_flush_log_at_trx_commit = 0 */
 
6014
 
 
6015
  log_buffer_flush_to_disk();
 
6016
 
 
6017
  /* Tell the InnoDB server that there might be work for
 
6018
  utility threads: */
 
6019
 
 
6020
  srv_active_wake_master_thread();
 
6021
 
 
6022
  innobase_commit_low(trx);
 
6023
 
 
6024
  trx_free_for_mysql(trx);
 
6025
 
 
6026
  if(error!=ENOENT)
 
6027
    error = convert_error_code_to_mysql(error, 0, NULL);
6028
6028
 
6029
6029
        if (error == 0 || error == ENOENT)
6030
6030
        {
6035
6035
          (void)internal::my_delete(path.c_str(), MYF(0));
6036
6036
        }
6037
6037
 
6038
 
        return(error);
 
6038
  return(error);
6039
6039
}
6040
6040
 
6041
6041
/*****************************************************************//**
6044
6044
InnobaseEngine::doDropSchema(
6045
6045
/*===================*/
6046
6046
                             SchemaIdentifier &identifier)
6047
 
                /*!< in: database path; inside InnoDB the name
6048
 
                        of the last directory in the path is used as
6049
 
                        the database name: for example, in 'mysql/data/test'
6050
 
                        the database name is 'test' */
 
6047
    /*!< in: database path; inside InnoDB the name
 
6048
      of the last directory in the path is used as
 
6049
      the database name: for example, in 'mysql/data/test'
 
6050
      the database name is 'test' */
6051
6051
{
6052
 
        trx_t*  trx;
6053
 
        int     error;
6054
 
        string schema_path(identifier.getPath());
6055
 
        Session*        session         = current_session;
6056
 
 
6057
 
        /* Get the transaction associated with the current session, or create one
6058
 
        if not yet created */
6059
 
 
6060
 
        assert(this == innodb_engine_ptr);
6061
 
 
6062
 
        /* In the Windows plugin, session = current_session is always NULL */
6063
 
        if (session) {
6064
 
                trx_t*  parent_trx = check_trx_exists(session);
6065
 
 
6066
 
                /* In case Drizzle calls this in the middle of a SELECT
6067
 
                query, release possible adaptive hash latch to avoid
6068
 
                deadlocks of threads */
6069
 
 
6070
 
                trx_search_latch_release_if_reserved(parent_trx);
6071
 
        }
 
6052
  trx_t*  trx;
 
6053
  int error;
 
6054
  string schema_path(identifier.getPath());
 
6055
  Session*  session   = current_session;
 
6056
 
 
6057
  /* Get the transaction associated with the current session, or create one
 
6058
  if not yet created */
 
6059
 
 
6060
  assert(this == innodb_engine_ptr);
 
6061
 
 
6062
  /* In the Windows plugin, session = current_session is always NULL */
 
6063
  if (session) {
 
6064
    trx_t*  parent_trx = check_trx_exists(session);
 
6065
 
 
6066
    /* In case Drizzle calls this in the middle of a SELECT
 
6067
    query, release possible adaptive hash latch to avoid
 
6068
    deadlocks of threads */
 
6069
 
 
6070
    trx_search_latch_release_if_reserved(parent_trx);
 
6071
  }
6072
6072
 
6073
6073
        schema_path.append("/");
6074
 
        trx = innobase_trx_allocate(session);
6075
 
        error = row_drop_database_for_mysql(schema_path.c_str(), trx);
6076
 
 
6077
 
        /* Flush the log to reduce probability that the .frm files and
6078
 
        the InnoDB data dictionary get out-of-sync if the user runs
6079
 
        with innodb_flush_log_at_trx_commit = 0 */
6080
 
 
6081
 
        log_buffer_flush_to_disk();
6082
 
 
6083
 
        /* Tell the InnoDB server that there might be work for
6084
 
        utility threads: */
6085
 
 
6086
 
        srv_active_wake_master_thread();
6087
 
 
6088
 
        innobase_commit_low(trx);
6089
 
        trx_free_for_mysql(trx);
 
6074
  trx = innobase_trx_allocate(session);
 
6075
  error = row_drop_database_for_mysql(schema_path.c_str(), trx);
 
6076
 
 
6077
  /* Flush the log to reduce probability that the .frm files and
 
6078
  the InnoDB data dictionary get out-of-sync if the user runs
 
6079
  with innodb_flush_log_at_trx_commit = 0 */
 
6080
 
 
6081
  log_buffer_flush_to_disk();
 
6082
 
 
6083
  /* Tell the InnoDB server that there might be work for
 
6084
  utility threads: */
 
6085
 
 
6086
  srv_active_wake_master_thread();
 
6087
 
 
6088
  innobase_commit_low(trx);
 
6089
  trx_free_for_mysql(trx);
6090
6090
 
6091
6091
        return false; // We are just a listener since we lack control over DDL, so we give no positive acknowledgement. 
6092
6092
}
6093
6093
/*********************************************************************//**
6094
6094
Renames an InnoDB table.
6095
 
@return 0 or error code */
 
6095
@return 0 or error code */
6096
6096
static
6097
6097
int
6098
6098
innobase_rename_table(
6099
6099
/*==================*/
6100
 
        trx_t*          trx,    /*!< in: transaction */
6101
 
        const char*     from,   /*!< in: old name of the table */
6102
 
        const char*     to,     /*!< in: new name of the table */
6103
 
        ibool           lock_and_commit)
6104
 
                                /*!< in: TRUE=lock data dictionary and commit */
 
6100
  trx_t*    trx,  /*!< in: transaction */
 
6101
  const char* from, /*!< in: old name of the table */
 
6102
  const char* to, /*!< in: new name of the table */
 
6103
  ibool   lock_and_commit)
 
6104
        /*!< in: TRUE=lock data dictionary and commit */
6105
6105
{
6106
 
        int     error;
6107
 
        char*   norm_to;
6108
 
        char*   norm_from;
6109
 
 
6110
 
        srv_lower_case_table_names = TRUE;
6111
 
 
6112
 
        // Magic number 64 arbitrary
6113
 
        norm_to = (char*) malloc(strlen(to) + 64);
6114
 
        norm_from = (char*) malloc(strlen(from) + 64);
6115
 
 
6116
 
        normalize_table_name(norm_to, to);
6117
 
        normalize_table_name(norm_from, from);
6118
 
 
6119
 
        /* Serialize data dictionary operations with dictionary mutex:
6120
 
        no deadlocks can occur then in these operations */
6121
 
 
6122
 
        if (lock_and_commit) {
6123
 
                row_mysql_lock_data_dictionary(trx);
6124
 
        }
6125
 
 
6126
 
        error = row_rename_table_for_mysql(
6127
 
                norm_from, norm_to, trx, lock_and_commit);
6128
 
 
6129
 
        if (error != DB_SUCCESS) {
6130
 
                FILE* ef = dict_foreign_err_file;
6131
 
 
6132
 
                fputs("InnoDB: Renaming table ", ef);
6133
 
                ut_print_name(ef, trx, TRUE, norm_from);
6134
 
                fputs(" to ", ef);
6135
 
                ut_print_name(ef, trx, TRUE, norm_to);
6136
 
                fputs(" failed!\n", ef);
6137
 
        }
6138
 
 
6139
 
        if (lock_and_commit) {
6140
 
                row_mysql_unlock_data_dictionary(trx);
6141
 
 
6142
 
                /* Flush the log to reduce probability that the .frm
6143
 
                files and the InnoDB data dictionary get out-of-sync
6144
 
                if the user runs with innodb_flush_log_at_trx_commit = 0 */
6145
 
 
6146
 
                log_buffer_flush_to_disk();
6147
 
        }
6148
 
 
6149
 
        free(norm_to);
6150
 
        free(norm_from);
6151
 
 
6152
 
        return error;
 
6106
  int error;
 
6107
  char* norm_to;
 
6108
  char* norm_from;
 
6109
 
 
6110
  srv_lower_case_table_names = TRUE;
 
6111
 
 
6112
  // Magic number 64 arbitrary
 
6113
  norm_to = (char*) malloc(strlen(to) + 64);
 
6114
  norm_from = (char*) malloc(strlen(from) + 64);
 
6115
 
 
6116
  normalize_table_name(norm_to, to);
 
6117
  normalize_table_name(norm_from, from);
 
6118
 
 
6119
  /* Serialize data dictionary operations with dictionary mutex:
 
6120
  no deadlocks can occur then in these operations */
 
6121
 
 
6122
  if (lock_and_commit) {
 
6123
    row_mysql_lock_data_dictionary(trx);
 
6124
  }
 
6125
 
 
6126
  error = row_rename_table_for_mysql(
 
6127
    norm_from, norm_to, trx, lock_and_commit);
 
6128
 
 
6129
  if (error != DB_SUCCESS) {
 
6130
    FILE* ef = dict_foreign_err_file;
 
6131
 
 
6132
    fputs("InnoDB: Renaming table ", ef);
 
6133
    ut_print_name(ef, trx, TRUE, norm_from);
 
6134
    fputs(" to ", ef);
 
6135
    ut_print_name(ef, trx, TRUE, norm_to);
 
6136
    fputs(" failed!\n", ef);
 
6137
  }
 
6138
 
 
6139
  if (lock_and_commit) {
 
6140
    row_mysql_unlock_data_dictionary(trx);
 
6141
 
 
6142
    /* Flush the log to reduce probability that the .frm
 
6143
    files and the InnoDB data dictionary get out-of-sync
 
6144
    if the user runs with innodb_flush_log_at_trx_commit = 0 */
 
6145
 
 
6146
    log_buffer_flush_to_disk();
 
6147
  }
 
6148
 
 
6149
  free(norm_to);
 
6150
  free(norm_from);
 
6151
 
 
6152
  return error;
6153
6153
}
6154
6154
/*********************************************************************//**
6155
6155
Renames an InnoDB table.
6156
 
@return 0 or error code */
 
6156
@return 0 or error code */
6157
6157
UNIV_INTERN int InnobaseEngine::doRenameTable(Session &session, TableIdentifier &from, TableIdentifier &to)
6158
6158
{
6159
6159
        // A temp table alter table/rename is a shallow rename and only the
6163
6163
          return plugin::StorageEngine::renameDefinitionFromPath(to, from);
6164
6164
        }
6165
6165
 
6166
 
        trx_t*  trx;
6167
 
        int     error;
6168
 
        trx_t*  parent_trx;
6169
 
 
6170
 
        /* Get the transaction associated with the current session, or create one
6171
 
        if not yet created */
6172
 
 
6173
 
        parent_trx = check_trx_exists(&session);
6174
 
 
6175
 
        /* In case MySQL calls this in the middle of a SELECT query, release
6176
 
        possible adaptive hash latch to avoid deadlocks of threads */
6177
 
 
6178
 
        trx_search_latch_release_if_reserved(parent_trx);
6179
 
 
6180
 
        trx = innobase_trx_allocate(&session);
6181
 
 
6182
 
        error = innobase_rename_table(trx, from.getPath().c_str(), to.getPath().c_str(), TRUE);
6183
 
 
6184
 
        /* Tell the InnoDB server that there might be work for
6185
 
        utility threads: */
6186
 
 
6187
 
        srv_active_wake_master_thread();
6188
 
 
6189
 
        innobase_commit_low(trx);
6190
 
        trx_free_for_mysql(trx);
6191
 
 
6192
 
        error = convert_error_code_to_mysql(error, 0, NULL);
 
6166
  trx_t*  trx;
 
6167
  int error;
 
6168
  trx_t*  parent_trx;
 
6169
 
 
6170
  /* Get the transaction associated with the current session, or create one
 
6171
  if not yet created */
 
6172
 
 
6173
  parent_trx = check_trx_exists(&session);
 
6174
 
 
6175
  /* In case MySQL calls this in the middle of a SELECT query, release
 
6176
  possible adaptive hash latch to avoid deadlocks of threads */
 
6177
 
 
6178
  trx_search_latch_release_if_reserved(parent_trx);
 
6179
 
 
6180
  trx = innobase_trx_allocate(&session);
 
6181
 
 
6182
  error = innobase_rename_table(trx, from.getPath().c_str(), to.getPath().c_str(), TRUE);
 
6183
 
 
6184
  /* Tell the InnoDB server that there might be work for
 
6185
  utility threads: */
 
6186
 
 
6187
  srv_active_wake_master_thread();
 
6188
 
 
6189
  innobase_commit_low(trx);
 
6190
  trx_free_for_mysql(trx);
 
6191
 
 
6192
  error = convert_error_code_to_mysql(error, 0, NULL);
6193
6193
 
6194
6194
        if (not error)
6195
6195
        {
6197
6197
          plugin::StorageEngine::renameDefinitionFromPath(to, from);
6198
6198
        }
6199
6199
 
6200
 
        return(error);
 
6200
  return(error);
6201
6201
}
6202
6202
 
6203
6203
/*********************************************************************//**
6204
6204
Estimates the number of index records in a range.
6205
 
@return estimated number of rows */
 
6205
@return estimated number of rows */
6206
6206
UNIV_INTERN
6207
6207
ha_rows
6208
6208
ha_innobase::records_in_range(
6209
6209
/*==========================*/
6210
 
        uint                    keynr,          /*!< in: index number */
6211
 
        key_range               *min_key,       /*!< in: start key value of the
6212
 
                                                   range, may also be 0 */
6213
 
        key_range               *max_key)       /*!< in: range end key val, may
6214
 
                                                   also be 0 */
 
6210
  uint      keynr,    /*!< in: index number */
 
6211
  key_range   *min_key, /*!< in: start key value of the
 
6212
               range, may also be 0 */
 
6213
  key_range   *max_key) /*!< in: range end key val, may
 
6214
               also be 0 */
6215
6215
{
6216
 
        KEY*            key;
6217
 
        dict_index_t*   index;
6218
 
        unsigned char*          key_val_buff2   = (unsigned char*) malloc(
6219
 
                                                  table->s->stored_rec_length
6220
 
                                        + table->s->max_key_length + 100);
6221
 
        ulint           buff2_len = table->s->stored_rec_length
6222
 
                                        + table->s->max_key_length + 100;
6223
 
        dtuple_t*       range_start;
6224
 
        dtuple_t*       range_end;
6225
 
        ib_int64_t      n_rows;
6226
 
        ulint           mode1;
6227
 
        ulint           mode2;
6228
 
        mem_heap_t*     heap;
6229
 
 
6230
 
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
6231
 
 
6232
 
        prebuilt->trx->op_info = (char*)"estimating records in index range";
6233
 
 
6234
 
        /* In case MySQL calls this in the middle of a SELECT query, release
6235
 
        possible adaptive hash latch to avoid deadlocks of threads */
6236
 
 
6237
 
        trx_search_latch_release_if_reserved(prebuilt->trx);
6238
 
 
6239
 
        active_index = keynr;
6240
 
 
6241
 
        key = table->key_info + active_index;
6242
 
 
6243
 
        index = dict_table_get_index_on_name(prebuilt->table, key->name);
6244
 
 
6245
 
        /* MySQL knows about this index and so we must be able to find it.*/
6246
 
        ut_a(index);
6247
 
 
6248
 
        heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
6249
 
                                    + sizeof(dtuple_t)));
6250
 
 
6251
 
        range_start = dtuple_create(heap, key->key_parts);
6252
 
        dict_index_copy_types(range_start, index, key->key_parts);
6253
 
 
6254
 
        range_end = dtuple_create(heap, key->key_parts);
6255
 
        dict_index_copy_types(range_end, index, key->key_parts);
6256
 
 
6257
 
        row_sel_convert_mysql_key_to_innobase(
6258
 
                                range_start, (byte*) key_val_buff,
6259
 
                                (ulint)upd_and_key_val_buff_len,
6260
 
                                index,
6261
 
                                (byte*) (min_key ? min_key->key :
6262
 
                                         (const unsigned char*) 0),
6263
 
                                (ulint) (min_key ? min_key->length : 0),
6264
 
                                prebuilt->trx);
6265
 
 
6266
 
        row_sel_convert_mysql_key_to_innobase(
6267
 
                                range_end, (byte*) key_val_buff2,
6268
 
                                buff2_len, index,
6269
 
                                (byte*) (max_key ? max_key->key :
6270
 
                                         (const unsigned char*) 0),
6271
 
                                (ulint) (max_key ? max_key->length : 0),
6272
 
                                prebuilt->trx);
6273
 
 
6274
 
        mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
6275
 
                                                HA_READ_KEY_EXACT);
6276
 
        mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
6277
 
                                                HA_READ_KEY_EXACT);
6278
 
 
6279
 
        if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
6280
 
 
6281
 
                n_rows = btr_estimate_n_rows_in_range(index, range_start,
6282
 
                                                      mode1, range_end,
6283
 
                                                      mode2);
6284
 
        } else {
6285
 
 
6286
 
                n_rows = HA_POS_ERROR;
6287
 
        }
6288
 
 
6289
 
        mem_heap_free(heap);
6290
 
 
6291
 
        free(key_val_buff2);
6292
 
 
6293
 
        prebuilt->trx->op_info = (char*)"";
6294
 
 
6295
 
        /* The MySQL optimizer seems to believe an estimate of 0 rows is
6296
 
        always accurate and may return the result 'Empty set' based on that.
6297
 
        The accuracy is not guaranteed, and even if it were, for a locking
6298
 
        read we should anyway perform the search to set the next-key lock.
6299
 
        Add 1 to the value to make sure MySQL does not make the assumption! */
6300
 
 
6301
 
        if (n_rows == 0) {
6302
 
                n_rows = 1;
6303
 
        }
6304
 
 
6305
 
        return((ha_rows) n_rows);
 
6216
  KEY*    key;
 
6217
  dict_index_t* index;
 
6218
  unsigned char*    key_val_buff2 = (unsigned char*) malloc(
 
6219
              table->s->stored_rec_length
 
6220
          + table->s->max_key_length + 100);
 
6221
  ulint   buff2_len = table->s->stored_rec_length
 
6222
          + table->s->max_key_length + 100;
 
6223
  dtuple_t* range_start;
 
6224
  dtuple_t* range_end;
 
6225
  ib_int64_t  n_rows;
 
6226
  ulint   mode1;
 
6227
  ulint   mode2;
 
6228
  mem_heap_t* heap;
 
6229
 
 
6230
  ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
6231
 
 
6232
  prebuilt->trx->op_info = (char*)"estimating records in index range";
 
6233
 
 
6234
  /* In case MySQL calls this in the middle of a SELECT query, release
 
6235
  possible adaptive hash latch to avoid deadlocks of threads */
 
6236
 
 
6237
  trx_search_latch_release_if_reserved(prebuilt->trx);
 
6238
 
 
6239
  active_index = keynr;
 
6240
 
 
6241
  key = table->key_info + active_index;
 
6242
 
 
6243
  index = dict_table_get_index_on_name(prebuilt->table, key->name);
 
6244
 
 
6245
  /* MySQL knows about this index and so we must be able to find it.*/
 
6246
  ut_a(index);
 
6247
 
 
6248
  heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
 
6249
            + sizeof(dtuple_t)));
 
6250
 
 
6251
  range_start = dtuple_create(heap, key->key_parts);
 
6252
  dict_index_copy_types(range_start, index, key->key_parts);
 
6253
 
 
6254
  range_end = dtuple_create(heap, key->key_parts);
 
6255
  dict_index_copy_types(range_end, index, key->key_parts);
 
6256
 
 
6257
  row_sel_convert_mysql_key_to_innobase(
 
6258
        range_start, (byte*) key_val_buff,
 
6259
        (ulint)upd_and_key_val_buff_len,
 
6260
        index,
 
6261
        (byte*) (min_key ? min_key->key :
 
6262
           (const unsigned char*) 0),
 
6263
        (ulint) (min_key ? min_key->length : 0),
 
6264
        prebuilt->trx);
 
6265
 
 
6266
  row_sel_convert_mysql_key_to_innobase(
 
6267
        range_end, (byte*) key_val_buff2,
 
6268
        buff2_len, index,
 
6269
        (byte*) (max_key ? max_key->key :
 
6270
           (const unsigned char*) 0),
 
6271
        (ulint) (max_key ? max_key->length : 0),
 
6272
        prebuilt->trx);
 
6273
 
 
6274
  mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
 
6275
            HA_READ_KEY_EXACT);
 
6276
  mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
 
6277
            HA_READ_KEY_EXACT);
 
6278
 
 
6279
  if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
 
6280
 
 
6281
    n_rows = btr_estimate_n_rows_in_range(index, range_start,
 
6282
                  mode1, range_end,
 
6283
                  mode2);
 
6284
  } else {
 
6285
 
 
6286
    n_rows = HA_POS_ERROR;
 
6287
  }
 
6288
 
 
6289
  mem_heap_free(heap);
 
6290
 
 
6291
  free(key_val_buff2);
 
6292
 
 
6293
  prebuilt->trx->op_info = (char*)"";
 
6294
 
 
6295
  /* The MySQL optimizer seems to believe an estimate of 0 rows is
 
6296
  always accurate and may return the result 'Empty set' based on that.
 
6297
  The accuracy is not guaranteed, and even if it were, for a locking
 
6298
  read we should anyway perform the search to set the next-key lock.
 
6299
  Add 1 to the value to make sure MySQL does not make the assumption! */
 
6300
 
 
6301
  if (n_rows == 0) {
 
6302
    n_rows = 1;
 
6303
  }
 
6304
 
 
6305
  return((ha_rows) n_rows);
6306
6306
}
6307
6307
 
6308
6308
/*********************************************************************//**
6309
6309
Gives an UPPER BOUND to the number of rows in a table. This is used in
6310
6310
filesort.cc.
6311
 
@return upper bound of rows */
 
6311
@return upper bound of rows */
6312
6312
UNIV_INTERN
6313
6313
ha_rows
6314
6314
ha_innobase::estimate_rows_upper_bound(void)
6315
6315
/*======================================*/
6316
6316
{
6317
 
        dict_index_t*   index;
6318
 
        uint64_t        estimate;
6319
 
        uint64_t        local_data_file_length;
6320
 
 
6321
 
        /* We do not know if MySQL can call this function before calling
6322
 
        external_lock(). To be safe, update the session of the current table
6323
 
        handle. */
6324
 
 
6325
 
        update_session(ha_session());
6326
 
 
6327
 
        prebuilt->trx->op_info = (char*)
6328
 
                                 "calculating upper bound for table rows";
6329
 
 
6330
 
        /* In case MySQL calls this in the middle of a SELECT query, release
6331
 
        possible adaptive hash latch to avoid deadlocks of threads */
6332
 
 
6333
 
        trx_search_latch_release_if_reserved(prebuilt->trx);
6334
 
 
6335
 
        index = dict_table_get_first_index(prebuilt->table);
6336
 
 
6337
 
        ut_a(index->stat_n_leaf_pages > 0);
6338
 
 
6339
 
        local_data_file_length =
6340
 
                ((uint64_t) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
6341
 
 
6342
 
 
6343
 
        /* Calculate a minimum length for a clustered index record and from
6344
 
        that an upper bound for the number of rows. Since we only calculate
6345
 
        new statistics in row0mysql.c when a table has grown by a threshold
6346
 
        factor, we must add a safety factor 2 in front of the formula below. */
6347
 
 
6348
 
        estimate = 2 * local_data_file_length /
6349
 
                                         dict_index_calc_min_rec_len(index);
6350
 
 
6351
 
        prebuilt->trx->op_info = (char*)"";
6352
 
 
6353
 
        return((ha_rows) estimate);
 
6317
  dict_index_t* index;
 
6318
  uint64_t  estimate;
 
6319
  uint64_t  local_data_file_length;
 
6320
 
 
6321
  /* We do not know if MySQL can call this function before calling
 
6322
  external_lock(). To be safe, update the session of the current table
 
6323
  handle. */
 
6324
 
 
6325
  update_session(ha_session());
 
6326
 
 
6327
  prebuilt->trx->op_info = (char*)
 
6328
         "calculating upper bound for table rows";
 
6329
 
 
6330
  /* In case MySQL calls this in the middle of a SELECT query, release
 
6331
  possible adaptive hash latch to avoid deadlocks of threads */
 
6332
 
 
6333
  trx_search_latch_release_if_reserved(prebuilt->trx);
 
6334
 
 
6335
  index = dict_table_get_first_index(prebuilt->table);
 
6336
 
 
6337
  ut_a(index->stat_n_leaf_pages > 0);
 
6338
 
 
6339
  local_data_file_length =
 
6340
    ((uint64_t) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
 
6341
 
 
6342
 
 
6343
  /* Calculate a minimum length for a clustered index record and from
 
6344
  that an upper bound for the number of rows. Since we only calculate
 
6345
  new statistics in row0mysql.c when a table has grown by a threshold
 
6346
  factor, we must add a safety factor 2 in front of the formula below. */
 
6347
 
 
6348
  estimate = 2 * local_data_file_length /
 
6349
           dict_index_calc_min_rec_len(index);
 
6350
 
 
6351
  prebuilt->trx->op_info = (char*)"";
 
6352
 
 
6353
  return((ha_rows) estimate);
6354
6354
}
6355
6355
 
6356
6356
/*********************************************************************//**
6357
6357
How many seeks it will take to read through the table. This is to be
6358
6358
comparable to the number returned by records_in_range so that we can
6359
6359
decide if we should scan the table or use keys.
6360
 
@return estimated time measured in disk seeks */
 
6360
@return estimated time measured in disk seeks */
6361
6361
UNIV_INTERN
6362
6362
double
6363
6363
ha_innobase::scan_time()
6364
6364
/*====================*/
6365
6365
{
6366
 
        /* Since MySQL seems to favor table scans too much over index
6367
 
        searches, we pretend that a sequential read takes the same time
6368
 
        as a random disk read, that is, we do not divide the following
6369
 
        by 10, which would be physically realistic. */
 
6366
  /* Since MySQL seems to favor table scans too much over index
 
6367
  searches, we pretend that a sequential read takes the same time
 
6368
  as a random disk read, that is, we do not divide the following
 
6369
  by 10, which would be physically realistic. */
6370
6370
 
6371
 
        return((double) (prebuilt->table->stat_clustered_index_size));
 
6371
  return((double) (prebuilt->table->stat_clustered_index_size));
6372
6372
}
6373
6373
 
6374
6374
/******************************************************************//**
6375
6375
Calculate the time it takes to read a set of ranges through an index
6376
6376
This enables us to optimise reads for clustered indexes.
6377
 
@return estimated time measured in disk seeks */
 
6377
@return estimated time measured in disk seeks */
6378
6378
UNIV_INTERN
6379
6379
double
6380
6380
ha_innobase::read_time(
6381
6381
/*===================*/
6382
 
        uint    index,  /*!< in: key number */
6383
 
        uint    ranges, /*!< in: how many ranges */
6384
 
        ha_rows rows)   /*!< in: estimated number of rows in the ranges */
 
6382
  uint  index,  /*!< in: key number */
 
6383
  uint  ranges, /*!< in: how many ranges */
 
6384
  ha_rows rows) /*!< in: estimated number of rows in the ranges */
6385
6385
{
6386
 
        ha_rows total_rows;
6387
 
        double  time_for_scan;
6388
 
 
6389
 
        if (index != table->s->primary_key) {
6390
 
                /* Not clustered */
6391
 
                return(Cursor::read_time(index, ranges, rows));
6392
 
        }
6393
 
 
6394
 
        if (rows <= 2) {
6395
 
 
6396
 
                return((double) rows);
6397
 
        }
6398
 
 
6399
 
        /* Assume that the read time is proportional to the scan time for all
6400
 
        rows + at most one seek per range. */
6401
 
 
6402
 
        time_for_scan = scan_time();
6403
 
 
6404
 
        if ((total_rows = estimate_rows_upper_bound()) < rows) {
6405
 
 
6406
 
                return(time_for_scan);
6407
 
        }
6408
 
 
6409
 
        return(ranges + (double) rows / (double) total_rows * time_for_scan);
 
6386
  ha_rows total_rows;
 
6387
  double  time_for_scan;
 
6388
 
 
6389
  if (index != table->s->primary_key) {
 
6390
    /* Not clustered */
 
6391
    return(Cursor::read_time(index, ranges, rows));
 
6392
  }
 
6393
 
 
6394
  if (rows <= 2) {
 
6395
 
 
6396
    return((double) rows);
 
6397
  }
 
6398
 
 
6399
  /* Assume that the read time is proportional to the scan time for all
 
6400
  rows + at most one seek per range. */
 
6401
 
 
6402
  time_for_scan = scan_time();
 
6403
 
 
6404
  if ((total_rows = estimate_rows_upper_bound()) < rows) {
 
6405
 
 
6406
    return(time_for_scan);
 
6407
  }
 
6408
 
 
6409
  return(ranges + (double) rows / (double) total_rows * time_for_scan);
6410
6410
}
6411
6411
 
6412
6412
/*********************************************************************//**
6416
6416
int
6417
6417
ha_innobase::info(
6418
6418
/*==============*/
6419
 
        uint flag)      /*!< in: what information MySQL requests */
 
6419
  uint flag)  /*!< in: what information MySQL requests */
6420
6420
{
6421
 
        dict_table_t*   ib_table;
6422
 
        dict_index_t*   index;
6423
 
        ha_rows         rec_per_key;
6424
 
        ib_int64_t      n_rows;
6425
 
        ulong           j;
6426
 
        ulong           i;
6427
 
        char            path[FN_REFLEN];
6428
 
        os_file_stat_t  stat_info;
6429
 
 
6430
 
        /* If we are forcing recovery at a high level, we will suppress
6431
 
        statistics calculation on tables, because that may crash the
6432
 
        server if an index is badly corrupted. */
6433
 
 
6434
 
        if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
6435
 
 
6436
 
                /* We return success (0) instead of HA_ERR_CRASHED,
6437
 
                because we want MySQL to process this query and not
6438
 
                stop, like it would do if it received the error code
6439
 
                HA_ERR_CRASHED. */
6440
 
 
6441
 
                return(0);
6442
 
        }
6443
 
 
6444
 
        /* We do not know if MySQL can call this function before calling
6445
 
        external_lock(). To be safe, update the session of the current table
6446
 
        handle. */
6447
 
 
6448
 
        update_session(ha_session());
6449
 
 
6450
 
        /* In case MySQL calls this in the middle of a SELECT query, release
6451
 
        possible adaptive hash latch to avoid deadlocks of threads */
6452
 
 
6453
 
        prebuilt->trx->op_info = (char*)"returning various info to MySQL";
6454
 
 
6455
 
        trx_search_latch_release_if_reserved(prebuilt->trx);
6456
 
 
6457
 
        ib_table = prebuilt->table;
6458
 
 
6459
 
        if (flag & HA_STATUS_TIME) {
6460
 
                if (innobase_stats_on_metadata) {
6461
 
                        /* In sql_show we call with this flag: update
6462
 
                        then statistics so that they are up-to-date */
6463
 
 
6464
 
                        prebuilt->trx->op_info = "updating table statistics";
6465
 
 
6466
 
                        dict_update_statistics(ib_table);
6467
 
 
6468
 
                        prebuilt->trx->op_info = "returning various info to MySQL";
6469
 
                }
6470
 
 
6471
 
                snprintf(path, sizeof(path), "%s/%s%s",
6472
 
                               drizzle_data_home, ib_table->name, ".dfe");
6473
 
 
6474
 
                internal::unpack_filename(path,path);
6475
 
 
6476
 
                /* Note that we do not know the access time of the table,
6477
 
                nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
6478
 
 
6479
 
                if (os_file_get_status(path,&stat_info)) {
6480
 
                        stats.create_time = (ulong) stat_info.ctime;
6481
 
                }
6482
 
        }
6483
 
 
6484
 
        if (flag & HA_STATUS_VARIABLE) {
6485
 
                n_rows = ib_table->stat_n_rows;
6486
 
 
6487
 
                /* Because we do not protect stat_n_rows by any mutex in a
6488
 
                delete, it is theoretically possible that the value can be
6489
 
                smaller than zero! TODO: fix this race.
6490
 
 
6491
 
                The MySQL optimizer seems to assume in a left join that n_rows
6492
 
                is an accurate estimate if it is zero. Of course, it is not,
6493
 
                since we do not have any locks on the rows yet at this phase.
6494
 
                Since SHOW TABLE STATUS seems to call this function with the
6495
 
                HA_STATUS_TIME flag set, while the left join optimizer does not
6496
 
                set that flag, we add one to a zero value if the flag is not
6497
 
                set. That way SHOW TABLE STATUS will show the best estimate,
6498
 
                while the optimizer never sees the table empty. */
6499
 
 
6500
 
                if (n_rows < 0) {
6501
 
                        n_rows = 0;
6502
 
                }
6503
 
 
6504
 
                if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
6505
 
                        n_rows++;
6506
 
                }
6507
 
 
6508
 
                /* Fix bug#40386: Not flushing query cache after truncate.
6509
 
                n_rows can not be 0 unless the table is empty, set to 1
6510
 
                instead. The original problem of bug#29507 is actually
6511
 
                fixed in the server code. */
6512
 
                if (session_sql_command(user_session) == SQLCOM_TRUNCATE) {
6513
 
 
6514
 
                        n_rows = 1;
6515
 
 
6516
 
                        /* We need to reset the prebuilt value too, otherwise
6517
 
                        checks for values greater than the last value written
6518
 
                        to the table will fail and the autoinc counter will
6519
 
                        not be updated. This will force write_row() into
6520
 
                        attempting an update of the table's AUTOINC counter. */
6521
 
 
6522
 
                        prebuilt->autoinc_last_value = 0;
6523
 
                }
6524
 
 
6525
 
                stats.records = (ha_rows)n_rows;
6526
 
                stats.deleted = 0;
6527
 
                stats.data_file_length = ((uint64_t)
6528
 
                                ib_table->stat_clustered_index_size)
6529
 
                                        * UNIV_PAGE_SIZE;
6530
 
                stats.index_file_length = ((uint64_t)
6531
 
                                ib_table->stat_sum_of_other_index_sizes)
6532
 
                                        * UNIV_PAGE_SIZE;
6533
 
 
6534
 
                /* Since fsp_get_available_space_in_free_extents() is
6535
 
                acquiring latches inside InnoDB, we do not call it if we
6536
 
                are asked by MySQL to avoid locking. Another reason to
6537
 
                avoid the call is that it uses quite a lot of CPU.
6538
 
                See Bug#38185.
6539
 
                We do not update delete_length if no locking is requested
6540
 
                so the "old" value can remain. delete_length is initialized
6541
 
                to 0 in the ha_statistics' constructor. */
6542
 
                if (!(flag & HA_STATUS_NO_LOCK)) {
6543
 
 
6544
 
                        /* lock the data dictionary to avoid races with
6545
 
                        ibd_file_missing and tablespace_discarded */
6546
 
                        row_mysql_lock_data_dictionary(prebuilt->trx);
6547
 
 
6548
 
                        /* ib_table->space must be an existent tablespace */
6549
 
                        if (!ib_table->ibd_file_missing
6550
 
                            && !ib_table->tablespace_discarded) {
6551
 
 
6552
 
                                stats.delete_length =
6553
 
                                        fsp_get_available_space_in_free_extents(
6554
 
                                                ib_table->space) * 1024;
6555
 
                        } else {
6556
 
 
6557
 
                                Session*        session;
6558
 
 
6559
 
                                session = ha_session();
6560
 
 
6561
 
                                push_warning_printf(
6562
 
                                        session,
6563
 
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
6564
 
                                        ER_CANT_GET_STAT,
6565
 
                                        "InnoDB: Trying to get the free "
6566
 
                                        "space for table %s but its "
6567
 
                                        "tablespace has been discarded or "
6568
 
                                        "the .ibd file is missing. Setting "
6569
 
                                        "the free space to zero.",
6570
 
                                        ib_table->name);
6571
 
 
6572
 
                                stats.delete_length = 0;
6573
 
                        }
6574
 
 
6575
 
                        row_mysql_unlock_data_dictionary(prebuilt->trx);
6576
 
                }
6577
 
 
6578
 
                stats.check_time = 0;
6579
 
 
6580
 
                if (stats.records == 0) {
6581
 
                        stats.mean_rec_length = 0;
6582
 
                } else {
6583
 
                        stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
6584
 
                }
6585
 
        }
6586
 
 
6587
 
        if (flag & HA_STATUS_CONST) {
6588
 
                index = dict_table_get_first_index(ib_table);
6589
 
 
6590
 
                if (prebuilt->clust_index_was_generated) {
6591
 
                        index = dict_table_get_next_index(index);
6592
 
                }
6593
 
 
6594
 
                for (i = 0; i < table->s->keys; i++) {
6595
 
                        if (index == NULL) {
6596
 
                                errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains fewer "
6597
 
                                                "indexes inside InnoDB than "
6598
 
                                                "are defined in the MySQL "
6599
 
                                                ".frm file. Have you mixed up "
6600
 
                                                ".frm files from different "
6601
 
                                                "installations? See "
6602
 
                                                REFMAN
6603
 
                                                "innodb-troubleshooting.html\n",
6604
 
                                                ib_table->name);
6605
 
                                break;
6606
 
                        }
6607
 
 
6608
 
                        for (j = 0; j < table->key_info[i].key_parts; j++) {
6609
 
 
6610
 
                                if (j + 1 > index->n_uniq) {
6611
 
                                        errmsg_printf(ERRMSG_LVL_ERROR, 
 
6421
  dict_table_t* ib_table;
 
6422
  dict_index_t* index;
 
6423
  ha_rows   rec_per_key;
 
6424
  ib_int64_t  n_rows;
 
6425
  ulong   j;
 
6426
  ulong   i;
 
6427
  char    path[FN_REFLEN];
 
6428
  os_file_stat_t  stat_info;
 
6429
 
 
6430
  /* If we are forcing recovery at a high level, we will suppress
 
6431
  statistics calculation on tables, because that may crash the
 
6432
  server if an index is badly corrupted. */
 
6433
 
 
6434
  if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
 
6435
 
 
6436
    /* We return success (0) instead of HA_ERR_CRASHED,
 
6437
    because we want MySQL to process this query and not
 
6438
    stop, like it would do if it received the error code
 
6439
    HA_ERR_CRASHED. */
 
6440
 
 
6441
    return(0);
 
6442
  }
 
6443
 
 
6444
  /* We do not know if MySQL can call this function before calling
 
6445
  external_lock(). To be safe, update the session of the current table
 
6446
  handle. */
 
6447
 
 
6448
  update_session(ha_session());
 
6449
 
 
6450
  /* In case MySQL calls this in the middle of a SELECT query, release
 
6451
  possible adaptive hash latch to avoid deadlocks of threads */
 
6452
 
 
6453
  prebuilt->trx->op_info = (char*)"returning various info to MySQL";
 
6454
 
 
6455
  trx_search_latch_release_if_reserved(prebuilt->trx);
 
6456
 
 
6457
  ib_table = prebuilt->table;
 
6458
 
 
6459
  if (flag & HA_STATUS_TIME) {
 
6460
    if (innobase_stats_on_metadata) {
 
6461
      /* In sql_show we call with this flag: update
 
6462
      then statistics so that they are up-to-date */
 
6463
 
 
6464
      prebuilt->trx->op_info = "updating table statistics";
 
6465
 
 
6466
      dict_update_statistics(ib_table);
 
6467
 
 
6468
      prebuilt->trx->op_info = "returning various info to MySQL";
 
6469
    }
 
6470
 
 
6471
    snprintf(path, sizeof(path), "%s/%s%s",
 
6472
             drizzle_data_home, ib_table->name, ".dfe");
 
6473
 
 
6474
    internal::unpack_filename(path,path);
 
6475
 
 
6476
    /* Note that we do not know the access time of the table,
 
6477
    nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
 
6478
 
 
6479
    if (os_file_get_status(path,&stat_info)) {
 
6480
      stats.create_time = (ulong) stat_info.ctime;
 
6481
    }
 
6482
  }
 
6483
 
 
6484
  if (flag & HA_STATUS_VARIABLE) {
 
6485
    n_rows = ib_table->stat_n_rows;
 
6486
 
 
6487
    /* Because we do not protect stat_n_rows by any mutex in a
 
6488
    delete, it is theoretically possible that the value can be
 
6489
    smaller than zero! TODO: fix this race.
 
6490
 
 
6491
    The MySQL optimizer seems to assume in a left join that n_rows
 
6492
    is an accurate estimate if it is zero. Of course, it is not,
 
6493
    since we do not have any locks on the rows yet at this phase.
 
6494
    Since SHOW TABLE STATUS seems to call this function with the
 
6495
    HA_STATUS_TIME flag set, while the left join optimizer does not
 
6496
    set that flag, we add one to a zero value if the flag is not
 
6497
    set. That way SHOW TABLE STATUS will show the best estimate,
 
6498
    while the optimizer never sees the table empty. */
 
6499
 
 
6500
    if (n_rows < 0) {
 
6501
      n_rows = 0;
 
6502
    }
 
6503
 
 
6504
    if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
 
6505
      n_rows++;
 
6506
    }
 
6507
 
 
6508
    /* Fix bug#40386: Not flushing query cache after truncate.
 
6509
    n_rows can not be 0 unless the table is empty, set to 1
 
6510
    instead. The original problem of bug#29507 is actually
 
6511
    fixed in the server code. */
 
6512
    if (session_sql_command(user_session) == SQLCOM_TRUNCATE) {
 
6513
 
 
6514
      n_rows = 1;
 
6515
 
 
6516
      /* We need to reset the prebuilt value too, otherwise
 
6517
      checks for values greater than the last value written
 
6518
      to the table will fail and the autoinc counter will
 
6519
      not be updated. This will force write_row() into
 
6520
      attempting an update of the table's AUTOINC counter. */
 
6521
 
 
6522
      prebuilt->autoinc_last_value = 0;
 
6523
    }
 
6524
 
 
6525
    stats.records = (ha_rows)n_rows;
 
6526
    stats.deleted = 0;
 
6527
    stats.data_file_length = ((uint64_t)
 
6528
        ib_table->stat_clustered_index_size)
 
6529
          * UNIV_PAGE_SIZE;
 
6530
    stats.index_file_length = ((uint64_t)
 
6531
        ib_table->stat_sum_of_other_index_sizes)
 
6532
          * UNIV_PAGE_SIZE;
 
6533
 
 
6534
    /* Since fsp_get_available_space_in_free_extents() is
 
6535
    acquiring latches inside InnoDB, we do not call it if we
 
6536
    are asked by MySQL to avoid locking. Another reason to
 
6537
    avoid the call is that it uses quite a lot of CPU.
 
6538
    See Bug#38185.
 
6539
    We do not update delete_length if no locking is requested
 
6540
    so the "old" value can remain. delete_length is initialized
 
6541
    to 0 in the ha_statistics' constructor. */
 
6542
    if (!(flag & HA_STATUS_NO_LOCK)) {
 
6543
 
 
6544
      /* lock the data dictionary to avoid races with
 
6545
      ibd_file_missing and tablespace_discarded */
 
6546
      row_mysql_lock_data_dictionary(prebuilt->trx);
 
6547
 
 
6548
      /* ib_table->space must be an existent tablespace */
 
6549
      if (!ib_table->ibd_file_missing
 
6550
          && !ib_table->tablespace_discarded) {
 
6551
 
 
6552
        stats.delete_length =
 
6553
          fsp_get_available_space_in_free_extents(
 
6554
            ib_table->space) * 1024;
 
6555
      } else {
 
6556
 
 
6557
        Session*  session;
 
6558
 
 
6559
        session = ha_session();
 
6560
 
 
6561
        push_warning_printf(
 
6562
          session,
 
6563
          DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
6564
          ER_CANT_GET_STAT,
 
6565
          "InnoDB: Trying to get the free "
 
6566
          "space for table %s but its "
 
6567
          "tablespace has been discarded or "
 
6568
          "the .ibd file is missing. Setting "
 
6569
          "the free space to zero.",
 
6570
          ib_table->name);
 
6571
 
 
6572
        stats.delete_length = 0;
 
6573
      }
 
6574
 
 
6575
      row_mysql_unlock_data_dictionary(prebuilt->trx);
 
6576
    }
 
6577
 
 
6578
    stats.check_time = 0;
 
6579
 
 
6580
    if (stats.records == 0) {
 
6581
      stats.mean_rec_length = 0;
 
6582
    } else {
 
6583
      stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
 
6584
    }
 
6585
  }
 
6586
 
 
6587
  if (flag & HA_STATUS_CONST) {
 
6588
    index = dict_table_get_first_index(ib_table);
 
6589
 
 
6590
    if (prebuilt->clust_index_was_generated) {
 
6591
      index = dict_table_get_next_index(index);
 
6592
    }
 
6593
 
 
6594
    for (i = 0; i < table->s->keys; i++) {
 
6595
      if (index == NULL) {
 
6596
        errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains fewer "
 
6597
            "indexes inside InnoDB than "
 
6598
            "are defined in the MySQL "
 
6599
            ".frm file. Have you mixed up "
 
6600
            ".frm files from different "
 
6601
            "installations? See "
 
6602
            REFMAN
 
6603
            "innodb-troubleshooting.html\n",
 
6604
            ib_table->name);
 
6605
        break;
 
6606
      }
 
6607
 
 
6608
      for (j = 0; j < table->key_info[i].key_parts; j++) {
 
6609
 
 
6610
        if (j + 1 > index->n_uniq) {
 
6611
          errmsg_printf(ERRMSG_LVL_ERROR, 
6612
6612
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
6613
6613
"statistics for %lu columns. Have you mixed up .frm files from different "
6614
6614
"installations? "
6615
6615
"See " REFMAN "innodb-troubleshooting.html\n",
6616
 
                                                        index->name,
6617
 
                                                        ib_table->name,
6618
 
                                                        (unsigned long)
6619
 
                                                        index->n_uniq, j + 1);
6620
 
                                        break;
6621
 
                                }
6622
 
 
6623
 
                                if (index->stat_n_diff_key_vals[j + 1] == 0) {
6624
 
 
6625
 
                                        rec_per_key = stats.records;
6626
 
                                } else {
6627
 
                                        rec_per_key = (ha_rows)(stats.records /
6628
 
                                         index->stat_n_diff_key_vals[j + 1]);
6629
 
                                }
6630
 
 
6631
 
                                /* Since MySQL seems to favor table scans
6632
 
                                too much over index searches, we pretend
6633
 
                                index selectivity is 2 times better than
6634
 
                                our estimate: */
6635
 
 
6636
 
                                rec_per_key = rec_per_key / 2;
6637
 
 
6638
 
                                if (rec_per_key == 0) {
6639
 
                                        rec_per_key = 1;
6640
 
                                }
6641
 
 
6642
 
                                table->key_info[i].rec_per_key[j]=
6643
 
                                  rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
6644
 
                                  (ulong) rec_per_key;
6645
 
                        }
6646
 
 
6647
 
                        index = dict_table_get_next_index(index);
6648
 
                }
6649
 
        }
6650
 
 
6651
 
        if (flag & HA_STATUS_ERRKEY) {
6652
 
                const dict_index_t*     err_index;
6653
 
 
6654
 
                ut_a(prebuilt->trx);
6655
 
                ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6656
 
 
6657
 
                err_index = trx_get_error_info(prebuilt->trx);
6658
 
 
6659
 
                if (err_index) {
6660
 
                        errkey = (unsigned int)
6661
 
                                row_get_mysql_key_number_for_index(err_index);
6662
 
                } else {
6663
 
                        errkey = (unsigned int) prebuilt->trx->error_key_num;
6664
 
                }
6665
 
        }
6666
 
 
6667
 
        if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
6668
 
                stats.auto_increment_value = innobase_peek_autoinc();
6669
 
        }
6670
 
 
6671
 
        prebuilt->trx->op_info = (char*)"";
6672
 
 
6673
 
        return(0);
 
6616
              index->name,
 
6617
              ib_table->name,
 
6618
              (unsigned long)
 
6619
              index->n_uniq, j + 1);
 
6620
          break;
 
6621
        }
 
6622
 
 
6623
        if (index->stat_n_diff_key_vals[j + 1] == 0) {
 
6624
 
 
6625
          rec_per_key = stats.records;
 
6626
        } else {
 
6627
          rec_per_key = (ha_rows)(stats.records /
 
6628
           index->stat_n_diff_key_vals[j + 1]);
 
6629
        }
 
6630
 
 
6631
        /* Since MySQL seems to favor table scans
 
6632
        too much over index searches, we pretend
 
6633
        index selectivity is 2 times better than
 
6634
        our estimate: */
 
6635
 
 
6636
        rec_per_key = rec_per_key / 2;
 
6637
 
 
6638
        if (rec_per_key == 0) {
 
6639
          rec_per_key = 1;
 
6640
        }
 
6641
 
 
6642
        table->key_info[i].rec_per_key[j]=
 
6643
          rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
 
6644
          (ulong) rec_per_key;
 
6645
      }
 
6646
 
 
6647
      index = dict_table_get_next_index(index);
 
6648
    }
 
6649
  }
 
6650
 
 
6651
  if (flag & HA_STATUS_ERRKEY) {
 
6652
    const dict_index_t* err_index;
 
6653
 
 
6654
    ut_a(prebuilt->trx);
 
6655
    ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
 
6656
 
 
6657
    err_index = trx_get_error_info(prebuilt->trx);
 
6658
 
 
6659
    if (err_index) {
 
6660
      errkey = (unsigned int)
 
6661
        row_get_mysql_key_number_for_index(err_index);
 
6662
    } else {
 
6663
      errkey = (unsigned int) prebuilt->trx->error_key_num;
 
6664
    }
 
6665
  }
 
6666
 
 
6667
  if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
 
6668
    stats.auto_increment_value = innobase_peek_autoinc();
 
6669
  }
 
6670
 
 
6671
  prebuilt->trx->op_info = (char*)"";
 
6672
 
 
6673
  return(0);
6674
6674
}
6675
6675
 
6676
6676
/**********************************************************************//**
6677
6677
Updates index cardinalities of the table, based on 8 random dives into
6678
6678
each index tree. This does NOT calculate exact statistics on the table.
6679
 
@return returns always 0 (success) */
 
6679
@return returns always 0 (success) */
6680
6680
UNIV_INTERN
6681
6681
int
6682
6682
ha_innobase::analyze(
6683
6683
/*=================*/
6684
 
        Session*)               /*!< in: connection thread handle */
 
6684
  Session*)   /*!< in: connection thread handle */
6685
6685
{
6686
 
        /* Simply call ::info() with all the flags */
6687
 
        info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
 
6686
  /* Simply call ::info() with all the flags */
 
6687
  info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
6688
6688
 
6689
 
        return(0);
 
6689
  return(0);
6690
6690
}
6691
6691
 
6692
6692
/*******************************************************************//**
6693
6693
Tries to check that an InnoDB table is not corrupted. If corruption is
6694
6694
noticed, prints to stderr information about it. In case of corruption
6695
6695
may also assert a failure and crash the server.
6696
 
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
 
6696
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
6697
6697
UNIV_INTERN
6698
6698
int
6699
6699
ha_innobase::check(
6700
6700
/*===============*/
6701
 
        Session*        session)        /*!< in: user thread handle */
 
6701
  Session*  session)  /*!< in: user thread handle */
6702
6702
{
6703
 
        ulint           ret;
6704
 
 
6705
 
        assert(session == ha_session());
6706
 
        ut_a(prebuilt->trx);
6707
 
        ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
6708
 
        ut_a(prebuilt->trx == session_to_trx(session));
6709
 
 
6710
 
        if (prebuilt->mysql_template == NULL) {
6711
 
                /* Build the template; we will use a dummy template
6712
 
                in index scans done in checking */
6713
 
 
6714
 
                build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
6715
 
        }
6716
 
 
6717
 
        ret = row_check_table_for_mysql(prebuilt);
6718
 
 
6719
 
        if (ret == DB_SUCCESS) {
6720
 
                return(HA_ADMIN_OK);
6721
 
        }
6722
 
 
6723
 
        return(HA_ADMIN_CORRUPT);
 
6703
  ulint   ret;
 
6704
 
 
6705
  assert(session == ha_session());
 
6706
  ut_a(prebuilt->trx);
 
6707
  ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
 
6708
  ut_a(prebuilt->trx == session_to_trx(session));
 
6709
 
 
6710
  if (prebuilt->mysql_template == NULL) {
 
6711
    /* Build the template; we will use a dummy template
 
6712
    in index scans done in checking */
 
6713
 
 
6714
    build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
 
6715
  }
 
6716
 
 
6717
  ret = row_check_table_for_mysql(prebuilt);
 
6718
 
 
6719
  if (ret == DB_SUCCESS) {
 
6720
    return(HA_ADMIN_OK);
 
6721
  }
 
6722
 
 
6723
  return(HA_ADMIN_CORRUPT);
6724
6724
}
6725
6725
 
6726
6726
/*************************************************************//**
6727
6727
Adds information about free space in the InnoDB tablespace to a table comment
6728
6728
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
6729
6729
foreign keys.
6730
 
@return table comment + InnoDB free space + info on foreign keys */
 
6730
@return table comment + InnoDB free space + info on foreign keys */
6731
6731
UNIV_INTERN
6732
6732
char*
6733
6733
ha_innobase::update_table_comment(
6734
6734
/*==============================*/
6735
 
        const char*     comment)/*!< in: table comment defined by user */
 
6735
  const char* comment)/*!< in: table comment defined by user */
6736
6736
{
6737
 
        uint    length = (uint) strlen(comment);
6738
 
        char*   str;
6739
 
        long    flen;
6740
 
 
6741
 
        /* We do not know if MySQL can call this function before calling
6742
 
        external_lock(). To be safe, update the session of the current table
6743
 
        handle. */
6744
 
 
6745
 
        if (length > 64000 - 3) {
6746
 
                return((char*)comment); /* string too long */
6747
 
        }
6748
 
 
6749
 
        update_session(ha_session());
6750
 
 
6751
 
        prebuilt->trx->op_info = (char*)"returning table comment";
6752
 
 
6753
 
        /* In case MySQL calls this in the middle of a SELECT query, release
6754
 
        possible adaptive hash latch to avoid deadlocks of threads */
6755
 
 
6756
 
        trx_search_latch_release_if_reserved(prebuilt->trx);
6757
 
        str = NULL;
6758
 
 
6759
 
        /* output the data to a temporary file */
6760
 
 
6761
 
        mutex_enter(&srv_dict_tmpfile_mutex);
6762
 
        rewind(srv_dict_tmpfile);
6763
 
 
6764
 
        fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
6765
 
                fsp_get_available_space_in_free_extents(
6766
 
                        prebuilt->table->space));
6767
 
 
6768
 
        dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
6769
 
                                prebuilt->trx, prebuilt->table);
6770
 
        flen = ftell(srv_dict_tmpfile);
6771
 
        if (flen < 0) {
6772
 
                flen = 0;
6773
 
        } else if (length + flen + 3 > 64000) {
6774
 
                flen = 64000 - 3 - length;
6775
 
        }
6776
 
 
6777
 
        /* allocate buffer for the full string, and
6778
 
        read the contents of the temporary file */
6779
 
 
6780
 
        str = (char*) malloc(length + flen + 3);
6781
 
 
6782
 
        if (str) {
6783
 
                char* pos       = str + length;
6784
 
                if (length) {
6785
 
                        memcpy(str, comment, length);
6786
 
                        *pos++ = ';';
6787
 
                        *pos++ = ' ';
6788
 
                }
6789
 
                rewind(srv_dict_tmpfile);
6790
 
                flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
6791
 
                pos[flen] = 0;
6792
 
        }
6793
 
 
6794
 
        mutex_exit(&srv_dict_tmpfile_mutex);
6795
 
 
6796
 
        prebuilt->trx->op_info = (char*)"";
6797
 
 
6798
 
        return(str ? str : (char*) comment);
 
6737
  uint  length = (uint) strlen(comment);
 
6738
  char* str;
 
6739
  long  flen;
 
6740
 
 
6741
  /* We do not know if MySQL can call this function before calling
 
6742
  external_lock(). To be safe, update the session of the current table
 
6743
  handle. */
 
6744
 
 
6745
  if (length > 64000 - 3) {
 
6746
    return((char*)comment); /* string too long */
 
6747
  }
 
6748
 
 
6749
  update_session(ha_session());
 
6750
 
 
6751
  prebuilt->trx->op_info = (char*)"returning table comment";
 
6752
 
 
6753
  /* In case MySQL calls this in the middle of a SELECT query, release
 
6754
  possible adaptive hash latch to avoid deadlocks of threads */
 
6755
 
 
6756
  trx_search_latch_release_if_reserved(prebuilt->trx);
 
6757
  str = NULL;
 
6758
 
 
6759
  /* output the data to a temporary file */
 
6760
 
 
6761
  mutex_enter(&srv_dict_tmpfile_mutex);
 
6762
  rewind(srv_dict_tmpfile);
 
6763
 
 
6764
  fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
 
6765
    fsp_get_available_space_in_free_extents(
 
6766
      prebuilt->table->space));
 
6767
 
 
6768
  dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
 
6769
        prebuilt->trx, prebuilt->table);
 
6770
  flen = ftell(srv_dict_tmpfile);
 
6771
  if (flen < 0) {
 
6772
    flen = 0;
 
6773
  } else if (length + flen + 3 > 64000) {
 
6774
    flen = 64000 - 3 - length;
 
6775
  }
 
6776
 
 
6777
  /* allocate buffer for the full string, and
 
6778
  read the contents of the temporary file */
 
6779
 
 
6780
  str = (char*) malloc(length + flen + 3);
 
6781
 
 
6782
  if (str) {
 
6783
    char* pos = str + length;
 
6784
    if (length) {
 
6785
      memcpy(str, comment, length);
 
6786
      *pos++ = ';';
 
6787
      *pos++ = ' ';
 
6788
    }
 
6789
    rewind(srv_dict_tmpfile);
 
6790
    flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
 
6791
    pos[flen] = 0;
 
6792
  }
 
6793
 
 
6794
  mutex_exit(&srv_dict_tmpfile_mutex);
 
6795
 
 
6796
  prebuilt->trx->op_info = (char*)"";
 
6797
 
 
6798
  return(str ? str : (char*) comment);
6799
6799
}
6800
6800
 
6801
6801
/*******************************************************************//**
6808
6808
ha_innobase::get_foreign_key_create_info(void)
6809
6809
/*==========================================*/
6810
6810
{
6811
 
        char*   str     = 0;
6812
 
        long    flen;
6813
 
 
6814
 
        ut_a(prebuilt != NULL);
6815
 
 
6816
 
        /* We do not know if MySQL can call this function before calling
6817
 
        external_lock(). To be safe, update the session of the current table
6818
 
        handle. */
6819
 
 
6820
 
        update_session(ha_session());
6821
 
 
6822
 
        prebuilt->trx->op_info = (char*)"getting info on foreign keys";
6823
 
 
6824
 
        /* In case MySQL calls this in the middle of a SELECT query,
6825
 
        release possible adaptive hash latch to avoid
6826
 
        deadlocks of threads */
6827
 
 
6828
 
        trx_search_latch_release_if_reserved(prebuilt->trx);
6829
 
 
6830
 
        mutex_enter(&srv_dict_tmpfile_mutex);
6831
 
        rewind(srv_dict_tmpfile);
6832
 
 
6833
 
        /* output the data to a temporary file */
6834
 
        dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
6835
 
                                prebuilt->trx, prebuilt->table);
6836
 
        prebuilt->trx->op_info = (char*)"";
6837
 
 
6838
 
        flen = ftell(srv_dict_tmpfile);
6839
 
        if (flen < 0) {
6840
 
                flen = 0;
6841
 
        } else if (flen > 64000 - 1) {
6842
 
                flen = 64000 - 1;
6843
 
        }
6844
 
 
6845
 
        /* allocate buffer for the string, and
6846
 
        read the contents of the temporary file */
6847
 
 
6848
 
        str = (char*) malloc(flen + 1);
6849
 
 
6850
 
        if (str) {
6851
 
                rewind(srv_dict_tmpfile);
6852
 
                flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
6853
 
                str[flen] = 0;
6854
 
        }
6855
 
 
6856
 
        mutex_exit(&srv_dict_tmpfile_mutex);
6857
 
 
6858
 
        return(str);
 
6811
  char* str = 0;
 
6812
  long  flen;
 
6813
 
 
6814
  ut_a(prebuilt != NULL);
 
6815
 
 
6816
  /* We do not know if MySQL can call this function before calling
 
6817
  external_lock(). To be safe, update the session of the current table
 
6818
  handle. */
 
6819
 
 
6820
  update_session(ha_session());
 
6821
 
 
6822
  prebuilt->trx->op_info = (char*)"getting info on foreign keys";
 
6823
 
 
6824
  /* In case MySQL calls this in the middle of a SELECT query,
 
6825
  release possible adaptive hash latch to avoid
 
6826
  deadlocks of threads */
 
6827
 
 
6828
  trx_search_latch_release_if_reserved(prebuilt->trx);
 
6829
 
 
6830
  mutex_enter(&srv_dict_tmpfile_mutex);
 
6831
  rewind(srv_dict_tmpfile);
 
6832
 
 
6833
  /* output the data to a temporary file */
 
6834
  dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
 
6835
        prebuilt->trx, prebuilt->table);
 
6836
  prebuilt->trx->op_info = (char*)"";
 
6837
 
 
6838
  flen = ftell(srv_dict_tmpfile);
 
6839
  if (flen < 0) {
 
6840
    flen = 0;
 
6841
  } else if (flen > 64000 - 1) {
 
6842
    flen = 64000 - 1;
 
6843
  }
 
6844
 
 
6845
  /* allocate buffer for the string, and
 
6846
  read the contents of the temporary file */
 
6847
 
 
6848
  str = (char*) malloc(flen + 1);
 
6849
 
 
6850
  if (str) {
 
6851
    rewind(srv_dict_tmpfile);
 
6852
    flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
 
6853
    str[flen] = 0;
 
6854
  }
 
6855
 
 
6856
  mutex_exit(&srv_dict_tmpfile_mutex);
 
6857
 
 
6858
  return(str);
6859
6859
}
6860
6860
 
6861
6861
 
6862
6862
UNIV_INTERN
6863
6863
int
6864
 
ha_innobase::get_foreign_key_list(Session *session, List<FOREIGN_KEY_INFO> *f_key_list)
 
6864
ha_innobase::get_foreign_key_list(Session *session, List<ForeignKeyInfo> *f_key_list)
6865
6865
{
6866
6866
  dict_foreign_t* foreign;
6867
6867
 
6873
6873
  foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
6874
6874
 
6875
6875
  while (foreign != NULL) {
6876
 
          uint i;
6877
 
          FOREIGN_KEY_INFO f_key_info;
6878
 
          LEX_STRING *name= 0;
6879
 
          uint ulen;
6880
 
          char uname[NAME_LEN+1];           /* Unencoded name */
6881
 
          char db_name[NAME_LEN+1];
6882
 
          const char *tmp_buff;
6883
 
 
6884
 
          tmp_buff= foreign->id;
6885
 
          i= 0;
6886
 
          while (tmp_buff[i] != '/')
6887
 
                  i++;
6888
 
          tmp_buff+= i + 1;
6889
 
          f_key_info.forein_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
6890
 
          tmp_buff= foreign->referenced_table_name;
6891
 
 
6892
 
          /* Database name */
6893
 
          i= 0;
6894
 
          while (tmp_buff[i] != '/')
6895
 
          {
6896
 
            db_name[i]= tmp_buff[i];
6897
 
            i++;
6898
 
          }
6899
 
          db_name[i]= 0;
6900
 
          ulen= filename_to_tablename(db_name, uname, sizeof(uname));
6901
 
          f_key_info.referenced_db = session->make_lex_string(NULL, uname, ulen, true);
6902
 
 
6903
 
          /* Table name */
6904
 
          tmp_buff+= i + 1;
6905
 
          ulen= filename_to_tablename(tmp_buff, uname, sizeof(uname));
6906
 
          f_key_info.referenced_table = session->make_lex_string(NULL, uname, ulen, true);
6907
 
 
6908
 
          for (i= 0;;) {
6909
 
                  tmp_buff= foreign->foreign_col_names[i];
6910
 
                  name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6911
 
                  f_key_info.foreign_fields.push_back(name);
6912
 
                  tmp_buff= foreign->referenced_col_names[i];
6913
 
                  name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
6914
 
                  f_key_info.referenced_fields.push_back(name);
6915
 
                  if (++i >= foreign->n_fields)
6916
 
                          break;
6917
 
          }
 
6876
 
 
6877
    uint i;
 
6878
    LEX_STRING *name = 0;
 
6879
      uint ulen;
 
6880
      char uname[NAME_LEN + 1];           /* Unencoded name */
 
6881
      char db_name[NAME_LEN + 1];
 
6882
    const char *tmp_buff;
 
6883
 
 
6884
    /** Foreign id **/
 
6885
    tmp_buff = foreign->id;
 
6886
    i = 0;
 
6887
    while (tmp_buff[i] != '/')
 
6888
      i++;
 
6889
    tmp_buff += i + 1;
 
6890
    LEX_STRING *tmp_foreign_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
 
6891
 
 
6892
      /* Database name */
 
6893
    tmp_buff = foreign->referenced_table_name;
 
6894
 
 
6895
    i= 0;
 
6896
    while (tmp_buff[i] != '/')
 
6897
      {
 
6898
        db_name[i]= tmp_buff[i];
 
6899
        i++;
 
6900
      }
 
6901
      db_name[i] = 0;
 
6902
      ulen= filename_to_tablename(db_name, uname, sizeof(uname));
 
6903
    LEX_STRING *tmp_referenced_db = session->make_lex_string(NULL, uname, ulen, true);
 
6904
 
 
6905
      /* Table name */
 
6906
    tmp_buff += i + 1;
 
6907
      ulen= filename_to_tablename(tmp_buff, uname, sizeof(uname));
 
6908
    LEX_STRING *tmp_referenced_table = session->make_lex_string(NULL, uname, ulen, true);
 
6909
 
 
6910
      /** Foreign Fields **/
 
6911
  List<LEX_STRING> tmp_foreign_fields;
 
6912
  List<LEX_STRING> tmp_referenced_fields;
 
6913
    for (i= 0;;) {
 
6914
      tmp_buff= foreign->foreign_col_names[i];
 
6915
      name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
 
6916
      tmp_foreign_fields.push_back(name);
 
6917
      tmp_buff= foreign->referenced_col_names[i];
 
6918
      name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
 
6919
      tmp_referenced_fields.push_back(name);
 
6920
      if (++i >= foreign->n_fields)
 
6921
        break;
 
6922
    }
6918
6923
 
6919
6924
          ulong length;
6920
6925
          if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
6937
6942
            length=8;
6938
6943
            tmp_buff= "RESTRICT";
6939
6944
          }
6940
 
          f_key_info.delete_method = session->make_lex_string(
6941
 
                  f_key_info.delete_method, tmp_buff, length, true);
 
6945
    LEX_STRING *tmp_delete_method = session->make_lex_string(NULL, tmp_buff, length, true);
6942
6946
 
6943
6947
 
6944
6948
          if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
6961
6965
            length=8;
6962
6966
            tmp_buff= "RESTRICT";
6963
6967
          }
6964
 
          f_key_info.update_method = session->make_lex_string(
6965
 
                  f_key_info.update_method, tmp_buff, length, true);
 
6968
    LEX_STRING *tmp_update_method = session->make_lex_string(NULL, tmp_buff, length, true);
 
6969
 
 
6970
    LEX_STRING *tmp_referenced_key_name = NULL;
 
6971
 
6966
6972
          if (foreign->referenced_index &&
6967
6973
              foreign->referenced_index->name)
6968
6974
          {
6969
 
            f_key_info.referenced_key_name = session->make_lex_string(
6970
 
                    f_key_info.referenced_key_name,
6971
 
                    foreign->referenced_index->name,
6972
 
                    strlen(foreign->referenced_index->name), true);
 
6975
        tmp_referenced_key_name = session->make_lex_string(NULL,
 
6976
        foreign->referenced_index->name, strlen(foreign->referenced_index->name), true);
6973
6977
          }
6974
 
          else
6975
 
            f_key_info.referenced_key_name= 0;
6976
 
 
6977
 
          FOREIGN_KEY_INFO *pf_key_info = (FOREIGN_KEY_INFO *)
6978
 
                  session_memdup(session, &f_key_info, sizeof(FOREIGN_KEY_INFO));
6979
 
          f_key_list->push_back(pf_key_info);
6980
 
          foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 
6978
 
 
6979
      ForeignKeyInfo f_key_info(
 
6980
        tmp_foreign_id, tmp_referenced_db, tmp_referenced_table,
 
6981
        tmp_update_method, tmp_delete_method, tmp_referenced_key_name,
 
6982
        tmp_foreign_fields, tmp_referenced_fields);
 
6983
 
 
6984
    ForeignKeyInfo *pf_key_info = (ForeignKeyInfo *)
 
6985
      session_memdup(session, &f_key_info, sizeof(ForeignKeyInfo));
 
6986
    f_key_list->push_back(pf_key_info);
 
6987
    foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
6981
6988
  }
6982
6989
  mutex_exit(&(dict_sys->mutex));
6983
6990
  prebuilt->trx->op_info = (char*)"";
6989
6996
Checks if ALTER TABLE may change the storage engine of the table.
6990
6997
Changing storage engines is not allowed for tables for which there
6991
6998
are foreign key constraints (parent or child tables).
6992
 
@return TRUE if can switch engines */
 
6999
@return TRUE if can switch engines */
6993
7000
UNIV_INTERN
6994
7001
bool
6995
7002
ha_innobase::can_switch_engines(void)
6996
7003
/*=================================*/
6997
7004
{
6998
 
        bool    can_switch;
6999
 
 
7000
 
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
7001
 
 
7002
 
        prebuilt->trx->op_info =
7003
 
                        "determining if there are foreign key constraints";
7004
 
        row_mysql_lock_data_dictionary(prebuilt->trx);
7005
 
 
7006
 
        can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
7007
 
                        && !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
7008
 
 
7009
 
        row_mysql_unlock_data_dictionary(prebuilt->trx);
7010
 
        prebuilt->trx->op_info = "";
7011
 
 
7012
 
        return(can_switch);
 
7005
  bool  can_switch;
 
7006
 
 
7007
  ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
7008
 
 
7009
  prebuilt->trx->op_info =
 
7010
      "determining if there are foreign key constraints";
 
7011
  row_mysql_lock_data_dictionary(prebuilt->trx);
 
7012
 
 
7013
  can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
 
7014
      && !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
 
7015
 
 
7016
  row_mysql_unlock_data_dictionary(prebuilt->trx);
 
7017
  prebuilt->trx->op_info = "";
 
7018
 
 
7019
  return(can_switch);
7013
7020
}
7014
7021
 
7015
7022
/*******************************************************************//**
7017
7024
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
7018
7025
delete is then allowed internally to resolve a duplicate key conflict in
7019
7026
REPLACE, not an update.
7020
 
@return > 0 if referenced by a FOREIGN KEY */
 
7027
@return > 0 if referenced by a FOREIGN KEY */
7021
7028
UNIV_INTERN
7022
7029
uint
7023
7030
ha_innobase::referenced_by_foreign_key(void)
7024
7031
/*========================================*/
7025
7032
{
7026
 
        if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
7027
 
 
7028
 
                return(1);
7029
 
        }
7030
 
 
7031
 
        return(0);
 
7033
  if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
 
7034
 
 
7035
    return(1);
 
7036
  }
 
7037
 
 
7038
  return(0);
7032
7039
}
7033
7040
 
7034
7041
/*******************************************************************//**
7038
7045
void
7039
7046
ha_innobase::free_foreign_key_create_info(
7040
7047
/*======================================*/
7041
 
        char*   str)    /*!< in, own: create info string to free */
 
7048
  char* str)  /*!< in, own: create info string to free */
7042
7049
{
7043
 
        if (str) {
7044
 
                free(str);
7045
 
        }
 
7050
  if (str) {
 
7051
    free(str);
 
7052
  }
7046
7053
}
7047
7054
 
7048
7055
/*******************************************************************//**
7049
7056
Tells something additional to the Cursor about how to do things.
7050
 
@return 0 or error number */
 
7057
@return 0 or error number */
7051
7058
UNIV_INTERN
7052
7059
int
7053
7060
ha_innobase::extra(
7054
7061
/*===============*/
7055
 
        enum ha_extra_function operation)
7056
 
                           /*!< in: HA_EXTRA_FLUSH or some other flag */
 
7062
  enum ha_extra_function operation)
 
7063
         /*!< in: HA_EXTRA_FLUSH or some other flag */
7057
7064
{
7058
 
        /* Warning: since it is not sure that MySQL calls external_lock
7059
 
        before calling this function, the trx field in prebuilt can be
7060
 
        obsolete! */
7061
 
 
7062
 
        switch (operation) {
7063
 
                case HA_EXTRA_FLUSH:
7064
 
                        if (prebuilt->blob_heap) {
7065
 
                                row_mysql_prebuilt_free_blob_heap(prebuilt);
7066
 
                        }
7067
 
                        break;
7068
 
                case HA_EXTRA_RESET_STATE:
7069
 
                        reset_template(prebuilt);
7070
 
                        break;
7071
 
                case HA_EXTRA_NO_KEYREAD:
7072
 
                        prebuilt->read_just_key = 0;
7073
 
                        break;
7074
 
                case HA_EXTRA_KEYREAD:
7075
 
                        prebuilt->read_just_key = 1;
7076
 
                        break;
7077
 
                case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
7078
 
                        prebuilt->keep_other_fields_on_keyread = 1;
7079
 
                        break;
7080
 
 
7081
 
                        /* IMPORTANT: prebuilt->trx can be obsolete in
7082
 
                        this method, because it is not sure that MySQL
7083
 
                        calls external_lock before this method with the
7084
 
                        parameters below.  We must not invoke update_session()
7085
 
                        either, because the calling threads may change.
7086
 
                        CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
7087
 
                case HA_EXTRA_IGNORE_DUP_KEY:
7088
 
                        session_to_trx(ha_session())->duplicates |= TRX_DUP_IGNORE;
7089
 
                        break;
7090
 
                case HA_EXTRA_WRITE_CAN_REPLACE:
7091
 
                        session_to_trx(ha_session())->duplicates |= TRX_DUP_REPLACE;
7092
 
                        break;
7093
 
                case HA_EXTRA_WRITE_CANNOT_REPLACE:
7094
 
                        session_to_trx(ha_session())->duplicates &= ~TRX_DUP_REPLACE;
7095
 
                        break;
7096
 
                case HA_EXTRA_NO_IGNORE_DUP_KEY:
7097
 
                        session_to_trx(ha_session())->duplicates &=
7098
 
                                ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
7099
 
                        break;
7100
 
                default:/* Do nothing */
7101
 
                        ;
7102
 
        }
7103
 
 
7104
 
        return(0);
 
7065
  /* Warning: since it is not sure that MySQL calls external_lock
 
7066
  before calling this function, the trx field in prebuilt can be
 
7067
  obsolete! */
 
7068
 
 
7069
  switch (operation) {
 
7070
    case HA_EXTRA_FLUSH:
 
7071
      if (prebuilt->blob_heap) {
 
7072
        row_mysql_prebuilt_free_blob_heap(prebuilt);
 
7073
      }
 
7074
      break;
 
7075
    case HA_EXTRA_RESET_STATE:
 
7076
      reset_template(prebuilt);
 
7077
      break;
 
7078
    case HA_EXTRA_NO_KEYREAD:
 
7079
      prebuilt->read_just_key = 0;
 
7080
      break;
 
7081
    case HA_EXTRA_KEYREAD:
 
7082
      prebuilt->read_just_key = 1;
 
7083
      break;
 
7084
    case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
 
7085
      prebuilt->keep_other_fields_on_keyread = 1;
 
7086
      break;
 
7087
 
 
7088
      /* IMPORTANT: prebuilt->trx can be obsolete in
 
7089
      this method, because it is not sure that MySQL
 
7090
      calls external_lock before this method with the
 
7091
      parameters below.  We must not invoke update_session()
 
7092
      either, because the calling threads may change.
 
7093
      CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
 
7094
    case HA_EXTRA_IGNORE_DUP_KEY:
 
7095
      session_to_trx(ha_session())->duplicates |= TRX_DUP_IGNORE;
 
7096
      break;
 
7097
    case HA_EXTRA_WRITE_CAN_REPLACE:
 
7098
      session_to_trx(ha_session())->duplicates |= TRX_DUP_REPLACE;
 
7099
      break;
 
7100
    case HA_EXTRA_WRITE_CANNOT_REPLACE:
 
7101
      session_to_trx(ha_session())->duplicates &= ~TRX_DUP_REPLACE;
 
7102
      break;
 
7103
    case HA_EXTRA_NO_IGNORE_DUP_KEY:
 
7104
      session_to_trx(ha_session())->duplicates &=
 
7105
        ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
 
7106
      break;
 
7107
    default:/* Do nothing */
 
7108
      ;
 
7109
  }
 
7110
 
 
7111
  return(0);
7105
7112
}
7106
7113
 
7107
7114
UNIV_INTERN
7108
7115
int
7109
7116
ha_innobase::reset()
7110
7117
{
7111
 
        if (prebuilt->blob_heap) {
7112
 
                row_mysql_prebuilt_free_blob_heap(prebuilt);
7113
 
        }
7114
 
 
7115
 
        reset_template(prebuilt);
7116
 
 
7117
 
        /* TODO: This should really be reset in reset_template() but for now
7118
 
        it's safer to do it explicitly here. */
7119
 
 
7120
 
        /* This is a statement level counter. */
7121
 
        prebuilt->autoinc_last_value = 0;
7122
 
 
7123
 
        return(0);
 
7118
  if (prebuilt->blob_heap) {
 
7119
    row_mysql_prebuilt_free_blob_heap(prebuilt);
 
7120
  }
 
7121
 
 
7122
  reset_template(prebuilt);
 
7123
 
 
7124
  /* TODO: This should really be reset in reset_template() but for now
 
7125
  it's safer to do it explicitly here. */
 
7126
 
 
7127
  /* This is a statement level counter. */
 
7128
  prebuilt->autoinc_last_value = 0;
 
7129
 
 
7130
  return(0);
7124
7131
}
7125
7132
 
7126
7133
/******************************************************************//**
7127
7134
Maps a MySQL trx isolation level code to the InnoDB isolation level code
7128
 
@return InnoDB isolation level */
 
7135
@return InnoDB isolation level */
7129
7136
static inline
7130
7137
ulint
7131
7138
innobase_map_isolation_level(
7132
7139
/*=========================*/
7133
 
        enum_tx_isolation       iso)    /*!< in: MySQL isolation level code */
 
7140
  enum_tx_isolation iso)  /*!< in: MySQL isolation level code */
7134
7141
{
7135
 
        switch(iso) {
7136
 
                case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
7137
 
                case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
7138
 
                case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
7139
 
                case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
7140
 
                default: ut_a(0); return(0);
7141
 
        }
 
7142
  switch(iso) {
 
7143
    case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
 
7144
    case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
 
7145
    case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
 
7146
    case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
 
7147
    default: ut_a(0); return(0);
 
7148
  }
7142
7149
}
7143
7150
 
7144
7151
/******************************************************************//**
7145
7152
As MySQL will execute an external lock for every new table it uses when it
7146
7153
starts to process an SQL statement.  We can use this function to store the pointer to
7147
7154
the Session in the handle.
7148
 
@return 0 */
 
7155
@return 0 */
7149
7156
UNIV_INTERN
7150
7157
int
7151
7158
ha_innobase::external_lock(
7152
7159
/*=======================*/
7153
 
        Session*        session,        /*!< in: handle to the user thread */
7154
 
        int     lock_type)      /*!< in: lock type */
 
7160
  Session*  session,  /*!< in: handle to the user thread */
 
7161
  int lock_type)  /*!< in: lock type */
7155
7162
{
7156
 
        update_session(session);
 
7163
  update_session(session);
7157
7164
 
7158
7165
  trx_t *trx= prebuilt->trx;
7159
7166
 
7160
 
        prebuilt->sql_stat_start = TRUE;
7161
 
        prebuilt->hint_need_to_fetch_extra_cols = 0;
7162
 
 
7163
 
        reset_template(prebuilt);
7164
 
 
7165
 
        if (lock_type == F_WRLCK) {
7166
 
 
7167
 
                /* If this is a SELECT, then it is in UPDATE TABLE ...
7168
 
                or SELECT ... FOR UPDATE */
7169
 
                prebuilt->select_lock_type = LOCK_X;
7170
 
                prebuilt->stored_select_lock_type = LOCK_X;
7171
 
        }
7172
 
 
7173
 
        if (lock_type != F_UNLCK) {
7174
 
                /* MySQL is setting a new table lock */
7175
 
 
7176
 
                if (trx->isolation_level == TRX_ISO_SERIALIZABLE
7177
 
                        && prebuilt->select_lock_type == LOCK_NONE
7178
 
                        && session_test_options(session,
7179
 
                                OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
7180
 
 
7181
 
                        /* To get serializable execution, we let InnoDB
7182
 
                        conceptually add 'LOCK IN SHARE MODE' to all SELECTs
7183
 
                        which otherwise would have been consistent reads. An
7184
 
                        exception is consistent reads in the AUTOCOMMIT=1 mode:
7185
 
                        we know that they are read-only transactions, and they
7186
 
                        can be serialized also if performed as consistent
7187
 
                        reads. */
7188
 
 
7189
 
                        prebuilt->select_lock_type = LOCK_S;
7190
 
                        prebuilt->stored_select_lock_type = LOCK_S;
7191
 
                }
7192
 
 
7193
 
                /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
7194
 
                TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
7195
 
                an InnoDB table lock if it is released immediately at the end
7196
 
                of LOCK TABLES, and InnoDB's table locks in that case cause
7197
 
                VERY easily deadlocks.
7198
 
 
7199
 
                We do not set InnoDB table locks if user has not explicitly
7200
 
                requested a table lock. Note that session_in_lock_tables(session)
7201
 
                can hold in some cases, e.g., at the start of a stored
7202
 
                procedure call (SQLCOM_CALL). */
7203
 
 
7204
 
                if (prebuilt->select_lock_type != LOCK_NONE) {
7205
 
                        trx->mysql_n_tables_locked++;
7206
 
                }
7207
 
 
7208
 
                prebuilt->mysql_has_locked = TRUE;
7209
 
 
7210
 
                return(0);
7211
 
        }
7212
 
 
7213
 
        /* MySQL is releasing a table lock */
7214
 
        prebuilt->mysql_has_locked = FALSE;
7215
 
        trx->mysql_n_tables_locked= 0;
7216
 
 
7217
 
        return(0);
 
7167
  prebuilt->sql_stat_start = TRUE;
 
7168
  prebuilt->hint_need_to_fetch_extra_cols = 0;
 
7169
 
 
7170
  reset_template(prebuilt);
 
7171
 
 
7172
  if (lock_type == F_WRLCK) {
 
7173
 
 
7174
    /* If this is a SELECT, then it is in UPDATE TABLE ...
 
7175
    or SELECT ... FOR UPDATE */
 
7176
    prebuilt->select_lock_type = LOCK_X;
 
7177
    prebuilt->stored_select_lock_type = LOCK_X;
 
7178
  }
 
7179
 
 
7180
  if (lock_type != F_UNLCK) {
 
7181
    /* MySQL is setting a new table lock */
 
7182
 
 
7183
    if (trx->isolation_level == TRX_ISO_SERIALIZABLE
 
7184
      && prebuilt->select_lock_type == LOCK_NONE
 
7185
      && session_test_options(session,
 
7186
        OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
7187
 
 
7188
      /* To get serializable execution, we let InnoDB
 
7189
      conceptually add 'LOCK IN SHARE MODE' to all SELECTs
 
7190
      which otherwise would have been consistent reads. An
 
7191
      exception is consistent reads in the AUTOCOMMIT=1 mode:
 
7192
      we know that they are read-only transactions, and they
 
7193
      can be serialized also if performed as consistent
 
7194
      reads. */
 
7195
 
 
7196
      prebuilt->select_lock_type = LOCK_S;
 
7197
      prebuilt->stored_select_lock_type = LOCK_S;
 
7198
    }
 
7199
 
 
7200
    /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
 
7201
    TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
 
7202
    an InnoDB table lock if it is released immediately at the end
 
7203
    of LOCK TABLES, and InnoDB's table locks in that case cause
 
7204
    VERY easily deadlocks.
 
7205
 
 
7206
    We do not set InnoDB table locks if user has not explicitly
 
7207
    requested a table lock. Note that session_in_lock_tables(session)
 
7208
    can hold in some cases, e.g., at the start of a stored
 
7209
    procedure call (SQLCOM_CALL). */
 
7210
 
 
7211
    if (prebuilt->select_lock_type != LOCK_NONE) {
 
7212
      trx->mysql_n_tables_locked++;
 
7213
    }
 
7214
 
 
7215
    prebuilt->mysql_has_locked = TRUE;
 
7216
 
 
7217
    return(0);
 
7218
  }
 
7219
 
 
7220
  /* MySQL is releasing a table lock */
 
7221
  prebuilt->mysql_has_locked = FALSE;
 
7222
  trx->mysql_n_tables_locked= 0;
 
7223
 
 
7224
  return(0);
7218
7225
}
7219
7226
 
7220
7227
/************************************************************************//**
7224
7231
bool
7225
7232
innodb_show_status(
7226
7233
/*===============*/
7227
 
        plugin::StorageEngine*  engine, /*!< in: the innodb StorageEngine */
7228
 
        Session*        session,/*!< in: the MySQL query thread of the caller */
7229
 
        stat_print_fn *stat_print)
 
7234
  plugin::StorageEngine*  engine, /*!< in: the innodb StorageEngine */
 
7235
  Session*  session,/*!< in: the MySQL query thread of the caller */
 
7236
  stat_print_fn *stat_print)
7230
7237
{
7231
 
        trx_t*                  trx;
7232
 
        static const char       truncated_msg[] = "... truncated...\n";
7233
 
        const long              MAX_STATUS_SIZE = 64000;
7234
 
        ulint                   trx_list_start = ULINT_UNDEFINED;
7235
 
        ulint                   trx_list_end = ULINT_UNDEFINED;
7236
 
 
7237
 
        assert(engine == innodb_engine_ptr);
7238
 
 
7239
 
        trx = check_trx_exists(session);
7240
 
 
7241
 
        innobase_release_stat_resources(trx);
7242
 
 
7243
 
        /* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
7244
 
        bytes of text. */
7245
 
 
7246
 
        long    flen, usable_len;
7247
 
        char*   str;
7248
 
 
7249
 
        mutex_enter(&srv_monitor_file_mutex);
7250
 
        rewind(srv_monitor_file);
7251
 
        srv_printf_innodb_monitor(srv_monitor_file,
7252
 
                                &trx_list_start, &trx_list_end);
7253
 
        flen = ftell(srv_monitor_file);
7254
 
        os_file_set_eof(srv_monitor_file);
7255
 
 
7256
 
        if (flen < 0) {
7257
 
                flen = 0;
7258
 
        }
7259
 
 
7260
 
        if (flen > MAX_STATUS_SIZE) {
7261
 
                usable_len = MAX_STATUS_SIZE;
7262
 
        } else {
7263
 
                usable_len = flen;
7264
 
        }
7265
 
 
7266
 
        /* allocate buffer for the string, and
7267
 
        read the contents of the temporary file */
7268
 
 
7269
 
        if (!(str = (char*) malloc(usable_len + 1))) {
7270
 
          mutex_exit(&srv_monitor_file_mutex);
7271
 
          return(TRUE);
7272
 
        }
7273
 
 
7274
 
        rewind(srv_monitor_file);
7275
 
        if (flen < MAX_STATUS_SIZE) {
7276
 
                /* Display the entire output. */
7277
 
                flen = (long) fread(str, 1, flen, srv_monitor_file);
7278
 
        } else if (trx_list_end < (ulint) flen
7279
 
                        && trx_list_start < trx_list_end
7280
 
                        && trx_list_start + (flen - trx_list_end)
7281
 
                        < MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
7282
 
                /* Omit the beginning of the list of active transactions. */
7283
 
                long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
7284
 
                memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
7285
 
                len += sizeof truncated_msg - 1;
7286
 
                usable_len = (MAX_STATUS_SIZE - 1) - len;
7287
 
                fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
7288
 
                len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
7289
 
                flen = len;
7290
 
        } else {
7291
 
                /* Omit the end of the output. */
7292
 
                flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
7293
 
        }
7294
 
 
7295
 
        mutex_exit(&srv_monitor_file_mutex);
7296
 
 
7297
 
        bool result = FALSE;
7298
 
 
7299
 
        if (stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
7300
 
                        STRING_WITH_LEN(""), str, flen)) {
7301
 
                result= TRUE;
7302
 
        }
7303
 
        free(str);
7304
 
 
7305
 
        return(FALSE);
 
7238
  trx_t*      trx;
 
7239
  static const char truncated_msg[] = "... truncated...\n";
 
7240
  const long    MAX_STATUS_SIZE = 64000;
 
7241
  ulint     trx_list_start = ULINT_UNDEFINED;
 
7242
  ulint     trx_list_end = ULINT_UNDEFINED;
 
7243
 
 
7244
  assert(engine == innodb_engine_ptr);
 
7245
 
 
7246
  trx = check_trx_exists(session);
 
7247
 
 
7248
  innobase_release_stat_resources(trx);
 
7249
 
 
7250
  /* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
 
7251
  bytes of text. */
 
7252
 
 
7253
  long  flen, usable_len;
 
7254
  char* str;
 
7255
 
 
7256
  mutex_enter(&srv_monitor_file_mutex);
 
7257
  rewind(srv_monitor_file);
 
7258
  srv_printf_innodb_monitor(srv_monitor_file,
 
7259
        &trx_list_start, &trx_list_end);
 
7260
  flen = ftell(srv_monitor_file);
 
7261
  os_file_set_eof(srv_monitor_file);
 
7262
 
 
7263
  if (flen < 0) {
 
7264
    flen = 0;
 
7265
  }
 
7266
 
 
7267
  if (flen > MAX_STATUS_SIZE) {
 
7268
    usable_len = MAX_STATUS_SIZE;
 
7269
  } else {
 
7270
    usable_len = flen;
 
7271
  }
 
7272
 
 
7273
  /* allocate buffer for the string, and
 
7274
  read the contents of the temporary file */
 
7275
 
 
7276
  if (!(str = (char*) malloc(usable_len + 1))) {
 
7277
    mutex_exit(&srv_monitor_file_mutex);
 
7278
    return(TRUE);
 
7279
  }
 
7280
 
 
7281
  rewind(srv_monitor_file);
 
7282
  if (flen < MAX_STATUS_SIZE) {
 
7283
    /* Display the entire output. */
 
7284
    flen = (long) fread(str, 1, flen, srv_monitor_file);
 
7285
  } else if (trx_list_end < (ulint) flen
 
7286
      && trx_list_start < trx_list_end
 
7287
      && trx_list_start + (flen - trx_list_end)
 
7288
      < MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
 
7289
    /* Omit the beginning of the list of active transactions. */
 
7290
    long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
 
7291
    memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
 
7292
    len += sizeof truncated_msg - 1;
 
7293
    usable_len = (MAX_STATUS_SIZE - 1) - len;
 
7294
    fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
 
7295
    len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
 
7296
    flen = len;
 
7297
  } else {
 
7298
    /* Omit the end of the output. */
 
7299
    flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
 
7300
  }
 
7301
 
 
7302
  mutex_exit(&srv_monitor_file_mutex);
 
7303
 
 
7304
  bool result = FALSE;
 
7305
 
 
7306
  if (stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
 
7307
      STRING_WITH_LEN(""), str, flen)) {
 
7308
    result= TRUE;
 
7309
  }
 
7310
  free(str);
 
7311
 
 
7312
  return(FALSE);
7306
7313
}
7307
7314
 
7308
7315
/************************************************************************//**
7311
7318
bool
7312
7319
innodb_mutex_show_status(
7313
7320
/*=====================*/
7314
 
        plugin::StorageEngine*  engine,         /*!< in: the innodb StorageEngine */
7315
 
        Session*        session,        /*!< in: the MySQL query thread of the
7316
 
                                        caller */
7317
 
        stat_print_fn*  stat_print)
 
7321
  plugin::StorageEngine*  engine,   /*!< in: the innodb StorageEngine */
 
7322
  Session*  session,  /*!< in: the MySQL query thread of the
 
7323
          caller */
 
7324
  stat_print_fn*  stat_print)
7318
7325
{
7319
 
        char buf1[IO_SIZE], buf2[IO_SIZE];
7320
 
        mutex_t*        mutex;
7321
 
        rw_lock_t*      lock;
 
7326
  char buf1[IO_SIZE], buf2[IO_SIZE];
 
7327
  mutex_t*  mutex;
 
7328
  rw_lock_t*  lock;
7322
7329
#ifdef UNIV_DEBUG
7323
 
        ulint     rw_lock_count= 0;
7324
 
        ulint     rw_lock_count_spin_loop= 0;
7325
 
        ulint     rw_lock_count_spin_rounds= 0;
7326
 
        ulint     rw_lock_count_os_wait= 0;
7327
 
        ulint     rw_lock_count_os_yield= 0;
7328
 
        uint64_t rw_lock_wait_time= 0;
 
7330
  ulint   rw_lock_count= 0;
 
7331
  ulint   rw_lock_count_spin_loop= 0;
 
7332
  ulint   rw_lock_count_spin_rounds= 0;
 
7333
  ulint   rw_lock_count_os_wait= 0;
 
7334
  ulint   rw_lock_count_os_yield= 0;
 
7335
  uint64_t rw_lock_wait_time= 0;
7329
7336
#endif /* UNIV_DEBUG */
7330
 
        uint      engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
7331
 
        assert(engine == innodb_engine_ptr);
7332
 
 
7333
 
        mutex_enter(&mutex_list_mutex);
7334
 
 
7335
 
        mutex = UT_LIST_GET_FIRST(mutex_list);
7336
 
 
7337
 
        while (mutex != NULL) {
7338
 
                if (mutex->count_os_wait == 0
7339
 
                    || buf_pool_is_block_mutex(mutex)) {
7340
 
                        goto next_mutex;
7341
 
                }
 
7337
  uint    engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
 
7338
  assert(engine == innodb_engine_ptr);
 
7339
 
 
7340
  mutex_enter(&mutex_list_mutex);
 
7341
 
 
7342
  mutex = UT_LIST_GET_FIRST(mutex_list);
 
7343
 
 
7344
  while (mutex != NULL) {
 
7345
    if (mutex->count_os_wait == 0
 
7346
        || buf_pool_is_block_mutex(mutex)) {
 
7347
      goto next_mutex;
 
7348
    }
7342
7349
#ifdef UNIV_DEBUG
7343
 
                if (mutex->mutex_type != 1) {
7344
 
                        if (mutex->count_using > 0) {
7345
 
                                buf1len= my_snprintf(buf1, sizeof(buf1),
7346
 
                                        "%s:%s",
7347
 
                                        mutex->cmutex_name, mutex->cfile_name);
7348
 
                                buf2len= my_snprintf(buf2, sizeof(buf2),
7349
 
                                        "count=%lu, spin_waits=%lu,"
7350
 
                                        " spin_rounds=%lu, "
7351
 
                                        "os_waits=%lu, os_yields=%lu,"
7352
 
                                        " os_wait_times=%lu",
7353
 
                                        mutex->count_using,
7354
 
                                        mutex->count_spin_loop,
7355
 
                                        mutex->count_spin_rounds,
7356
 
                                        mutex->count_os_wait,
7357
 
                                        mutex->count_os_yield,
7358
 
                                        (ulong) (mutex->lspent_time/1000));
 
7350
    if (mutex->mutex_type != 1) {
 
7351
      if (mutex->count_using > 0) {
 
7352
        buf1len= my_snprintf(buf1, sizeof(buf1),
 
7353
          "%s:%s",
 
7354
          mutex->cmutex_name, mutex->cfile_name);
 
7355
        buf2len= my_snprintf(buf2, sizeof(buf2),
 
7356
          "count=%lu, spin_waits=%lu,"
 
7357
          " spin_rounds=%lu, "
 
7358
          "os_waits=%lu, os_yields=%lu,"
 
7359
          " os_wait_times=%lu",
 
7360
          mutex->count_using,
 
7361
          mutex->count_spin_loop,
 
7362
          mutex->count_spin_rounds,
 
7363
          mutex->count_os_wait,
 
7364
          mutex->count_os_yield,
 
7365
          (ulong) (mutex->lspent_time/1000));
7359
7366
 
7360
 
                                if (stat_print(session, innobase_engine_name,
7361
 
                                                engine_name_len, buf1, buf1len,
7362
 
                                                buf2, buf2len)) {
7363
 
                                        mutex_exit(&mutex_list_mutex);
7364
 
                                        return(1);
7365
 
                                }
7366
 
                        }
7367
 
                }
7368
 
                else {
7369
 
                        rw_lock_count += mutex->count_using;
7370
 
                        rw_lock_count_spin_loop += mutex->count_spin_loop;
7371
 
                        rw_lock_count_spin_rounds += mutex->count_spin_rounds;
7372
 
                        rw_lock_count_os_wait += mutex->count_os_wait;
7373
 
                        rw_lock_count_os_yield += mutex->count_os_yield;
7374
 
                        rw_lock_wait_time += mutex->lspent_time;
7375
 
                }
 
7367
        if (stat_print(session, innobase_engine_name,
 
7368
            engine_name_len, buf1, buf1len,
 
7369
            buf2, buf2len)) {
 
7370
          mutex_exit(&mutex_list_mutex);
 
7371
          return(1);
 
7372
        }
 
7373
      }
 
7374
    }
 
7375
    else {
 
7376
      rw_lock_count += mutex->count_using;
 
7377
      rw_lock_count_spin_loop += mutex->count_spin_loop;
 
7378
      rw_lock_count_spin_rounds += mutex->count_spin_rounds;
 
7379
      rw_lock_count_os_wait += mutex->count_os_wait;
 
7380
      rw_lock_count_os_yield += mutex->count_os_yield;
 
7381
      rw_lock_wait_time += mutex->lspent_time;
 
7382
    }
7376
7383
#else /* UNIV_DEBUG */
7377
 
                buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
7378
 
                                  mutex->cfile_name, (ulong) mutex->cline);
7379
 
                buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
7380
 
                                  mutex->count_os_wait);
 
7384
    buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
 
7385
          mutex->cfile_name, (ulong) mutex->cline);
 
7386
    buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
 
7387
          mutex->count_os_wait);
7381
7388
 
7382
 
                if (stat_print(session, innobase_engine_name,
7383
 
                               engine_name_len, buf1, buf1len,
7384
 
                               buf2, buf2len)) {
7385
 
                        mutex_exit(&mutex_list_mutex);
7386
 
                        return(1);
7387
 
                }
 
7389
    if (stat_print(session, innobase_engine_name,
 
7390
             engine_name_len, buf1, buf1len,
 
7391
             buf2, buf2len)) {
 
7392
      mutex_exit(&mutex_list_mutex);
 
7393
      return(1);
 
7394
    }
7388
7395
#endif /* UNIV_DEBUG */
7389
7396
 
7390
7397
next_mutex:
7391
 
                mutex = UT_LIST_GET_NEXT(list, mutex);
7392
 
        }
7393
 
 
7394
 
        mutex_exit(&mutex_list_mutex);
7395
 
 
7396
 
        mutex_enter(&rw_lock_list_mutex);
7397
 
 
7398
 
        lock = UT_LIST_GET_FIRST(rw_lock_list);
7399
 
 
7400
 
        while (lock != NULL) {
7401
 
                if (lock->count_os_wait
 
7398
    mutex = UT_LIST_GET_NEXT(list, mutex);
 
7399
  }
 
7400
 
 
7401
  mutex_exit(&mutex_list_mutex);
 
7402
 
 
7403
  mutex_enter(&rw_lock_list_mutex);
 
7404
 
 
7405
  lock = UT_LIST_GET_FIRST(rw_lock_list);
 
7406
 
 
7407
  while (lock != NULL) {
 
7408
    if (lock->count_os_wait
7402
7409
                    && !buf_pool_is_block_lock(lock)) {
7403
 
                        buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
 
7410
      buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
7404
7411
                                    lock->cfile_name, (unsigned long) lock->cline);
7405
 
                        buf2len= snprintf(buf2, sizeof(buf2),
 
7412
      buf2len= snprintf(buf2, sizeof(buf2),
7406
7413
                                    "os_waits=%lu", lock->count_os_wait);
7407
7414
 
7408
 
                        if (stat_print(session, innobase_engine_name,
7409
 
                                       engine_name_len, buf1, buf1len,
7410
 
                                       buf2, buf2len)) {
7411
 
                                mutex_exit(&rw_lock_list_mutex);
7412
 
                                return(1);
7413
 
                        }
7414
 
                }
7415
 
                lock = UT_LIST_GET_NEXT(list, lock);
7416
 
        }
 
7415
      if (stat_print(session, innobase_engine_name,
 
7416
               engine_name_len, buf1, buf1len,
 
7417
               buf2, buf2len)) {
 
7418
        mutex_exit(&rw_lock_list_mutex);
 
7419
        return(1);
 
7420
      }
 
7421
    }
 
7422
    lock = UT_LIST_GET_NEXT(list, lock);
 
7423
  }
7417
7424
 
7418
 
        mutex_exit(&rw_lock_list_mutex);
 
7425
  mutex_exit(&rw_lock_list_mutex);
7419
7426
 
7420
7427
#ifdef UNIV_DEBUG
7421
 
        buf2len= my_snprintf(buf2, sizeof(buf2),
7422
 
                "count=%lu, spin_waits=%lu, spin_rounds=%lu, "
7423
 
                "os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
7424
 
                rw_lock_count, rw_lock_count_spin_loop,
7425
 
                rw_lock_count_spin_rounds,
7426
 
                rw_lock_count_os_wait, rw_lock_count_os_yield,
7427
 
                (ulong) (rw_lock_wait_time/1000));
 
7428
  buf2len= my_snprintf(buf2, sizeof(buf2),
 
7429
    "count=%lu, spin_waits=%lu, spin_rounds=%lu, "
 
7430
    "os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
 
7431
    rw_lock_count, rw_lock_count_spin_loop,
 
7432
    rw_lock_count_spin_rounds,
 
7433
    rw_lock_count_os_wait, rw_lock_count_os_yield,
 
7434
    (ulong) (rw_lock_wait_time/1000));
7428
7435
 
7429
 
        if (stat_print(session, innobase_engine_name, engine_name_len,
7430
 
                        STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
7431
 
                return(1);
7432
 
        }
 
7436
  if (stat_print(session, innobase_engine_name, engine_name_len,
 
7437
      STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
 
7438
    return(1);
 
7439
  }
7433
7440
#endif /* UNIV_DEBUG */
7434
7441
 
7435
 
        return(FALSE);
 
7442
  return(FALSE);
7436
7443
}
7437
7444
 
7438
7445
bool InnobaseEngine::show_status(Session* session, 
7439
7446
                                 stat_print_fn* stat_print,
7440
7447
                                 enum ha_stat_type stat_type)
7441
7448
{
7442
 
        assert(this == innodb_engine_ptr);
 
7449
  assert(this == innodb_engine_ptr);
7443
7450
 
7444
 
        switch (stat_type) {
7445
 
        case HA_ENGINE_STATUS:
7446
 
                return innodb_show_status(this, session, stat_print);
7447
 
        case HA_ENGINE_MUTEX:
7448
 
                return innodb_mutex_show_status(this, session, stat_print);
7449
 
        default:
7450
 
                return(FALSE);
7451
 
        }
 
7451
  switch (stat_type) {
 
7452
  case HA_ENGINE_STATUS:
 
7453
    return innodb_show_status(this, session, stat_print);
 
7454
  case HA_ENGINE_MUTEX:
 
7455
    return innodb_mutex_show_status(this, session, stat_print);
 
7456
  default:
 
7457
    return(FALSE);
 
7458
  }
7452
7459
}
7453
7460
 
7454
7461
/************************************************************************//**
7458
7465
 
7459
7466
static INNOBASE_SHARE* get_share(const char* table_name)
7460
7467
{
7461
 
        INNOBASE_SHARE *share;
7462
 
        pthread_mutex_lock(&innobase_share_mutex);
7463
 
 
7464
 
        ulint   fold = ut_fold_string(table_name);
7465
 
 
7466
 
        HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
7467
 
                    INNOBASE_SHARE*, share,
7468
 
                    ut_ad(share->use_count > 0),
7469
 
                    !strcmp(share->table_name, table_name));
7470
 
 
7471
 
        if (!share) {
7472
 
 
7473
 
                uint length = (uint) strlen(table_name);
7474
 
 
7475
 
                /* TODO: invoke HASH_MIGRATE if innobase_open_tables
7476
 
                grows too big */
7477
 
 
7478
 
                share = (INNOBASE_SHARE *) malloc(sizeof(*share)+length+1);
 
7468
  INNOBASE_SHARE *share;
 
7469
  pthread_mutex_lock(&innobase_share_mutex);
 
7470
 
 
7471
  ulint fold = ut_fold_string(table_name);
 
7472
 
 
7473
  HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
 
7474
        INNOBASE_SHARE*, share,
 
7475
        ut_ad(share->use_count > 0),
 
7476
        !strcmp(share->table_name, table_name));
 
7477
 
 
7478
  if (!share) {
 
7479
 
 
7480
    uint length = (uint) strlen(table_name);
 
7481
 
 
7482
    /* TODO: invoke HASH_MIGRATE if innobase_open_tables
 
7483
    grows too big */
 
7484
 
 
7485
    share = (INNOBASE_SHARE *) malloc(sizeof(*share)+length+1);
7479
7486
                memset(share, 0, sizeof(*share)+length+1);
7480
7487
 
7481
 
                share->table_name = (char*) memcpy(share + 1,
7482
 
                                                   table_name, length + 1);
7483
 
 
7484
 
                HASH_INSERT(INNOBASE_SHARE, table_name_hash,
7485
 
                            innobase_open_tables, fold, share);
7486
 
 
7487
 
                thr_lock_init(&share->lock);
7488
 
        }
7489
 
 
7490
 
        share->use_count++;
7491
 
        pthread_mutex_unlock(&innobase_share_mutex);
7492
 
 
7493
 
        return(share);
 
7488
    share->table_name = (char*) memcpy(share + 1,
 
7489
               table_name, length + 1);
 
7490
 
 
7491
    HASH_INSERT(INNOBASE_SHARE, table_name_hash,
 
7492
          innobase_open_tables, fold, share);
 
7493
 
 
7494
    thr_lock_init(&share->lock);
 
7495
  }
 
7496
 
 
7497
  share->use_count++;
 
7498
  pthread_mutex_unlock(&innobase_share_mutex);
 
7499
 
 
7500
  return(share);
7494
7501
}
7495
7502
 
7496
7503
static void free_share(INNOBASE_SHARE* share)
7497
7504
{
7498
 
        pthread_mutex_lock(&innobase_share_mutex);
 
7505
  pthread_mutex_lock(&innobase_share_mutex);
7499
7506
 
7500
7507
#ifdef UNIV_DEBUG
7501
 
        INNOBASE_SHARE* share2;
7502
 
        ulint   fold = ut_fold_string(share->table_name);
7503
 
 
7504
 
        HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
7505
 
                    INNOBASE_SHARE*, share2,
7506
 
                    ut_ad(share->use_count > 0),
7507
 
                    !strcmp(share->table_name, share2->table_name));
7508
 
 
7509
 
        ut_a(share2 == share);
 
7508
  INNOBASE_SHARE* share2;
 
7509
  ulint fold = ut_fold_string(share->table_name);
 
7510
 
 
7511
  HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
 
7512
        INNOBASE_SHARE*, share2,
 
7513
        ut_ad(share->use_count > 0),
 
7514
        !strcmp(share->table_name, share2->table_name));
 
7515
 
 
7516
  ut_a(share2 == share);
7510
7517
#endif /* UNIV_DEBUG */
7511
7518
 
7512
 
        if (!--share->use_count) {
7513
 
                ulint   fold = ut_fold_string(share->table_name);
7514
 
 
7515
 
                HASH_DELETE(INNOBASE_SHARE, table_name_hash,
7516
 
                            innobase_open_tables, fold, share);
7517
 
                thr_lock_delete(&share->lock);
7518
 
                free(share);
7519
 
 
7520
 
                /* TODO: invoke HASH_MIGRATE if innobase_open_tables
7521
 
                shrinks too much */
7522
 
        }
7523
 
 
7524
 
        pthread_mutex_unlock(&innobase_share_mutex);
 
7519
  if (!--share->use_count) {
 
7520
    ulint fold = ut_fold_string(share->table_name);
 
7521
 
 
7522
    HASH_DELETE(INNOBASE_SHARE, table_name_hash,
 
7523
          innobase_open_tables, fold, share);
 
7524
    thr_lock_delete(&share->lock);
 
7525
    free(share);
 
7526
 
 
7527
    /* TODO: invoke HASH_MIGRATE if innobase_open_tables
 
7528
    shrinks too much */
 
7529
  }
 
7530
 
 
7531
  pthread_mutex_unlock(&innobase_share_mutex);
7525
7532
}
7526
7533
 
7527
7534
/*****************************************************************//**
7532
7539
SELECT the read lock is released early on the 'const' tables where we only
7533
7540
fetch one row. MySQL does not call this when it releases all locks at the
7534
7541
end of an SQL statement.
7535
 
@return pointer to the next element in the 'to' array */
 
7542
@return pointer to the next element in the 'to' array */
7536
7543
UNIV_INTERN
7537
7544
THR_LOCK_DATA**
7538
7545
ha_innobase::store_lock(
7539
7546
/*====================*/
7540
 
        Session*                session,        /*!< in: user thread handle */
7541
 
        THR_LOCK_DATA**         to,             /*!< in: pointer to an array
7542
 
                                                of pointers to lock structs;
7543
 
                                                pointer to the 'lock' field
7544
 
                                                of current handle is stored
7545
 
                                                next to this array */
7546
 
        enum thr_lock_type      lock_type)      /*!< in: lock type to store in
7547
 
                                                'lock'; this may also be
7548
 
                                                TL_IGNORE */
 
7547
  Session*    session,  /*!< in: user thread handle */
 
7548
  THR_LOCK_DATA**   to,   /*!< in: pointer to an array
 
7549
            of pointers to lock structs;
 
7550
            pointer to the 'lock' field
 
7551
            of current handle is stored
 
7552
            next to this array */
 
7553
  enum thr_lock_type  lock_type)  /*!< in: lock type to store in
 
7554
            'lock'; this may also be
 
7555
            TL_IGNORE */
7549
7556
{
7550
 
        trx_t*          trx;
7551
 
 
7552
 
        /* Note that trx in this function is NOT necessarily prebuilt->trx
7553
 
        because we call update_session() later, in ::external_lock()! Failure to
7554
 
        understand this caused a serious memory corruption bug in 5.1.11. */
7555
 
 
7556
 
        trx = check_trx_exists(session);
7557
 
 
7558
 
        assert(EQ_CURRENT_SESSION(session));
7559
 
        const uint32_t sql_command = session_sql_command(session);
7560
 
 
7561
 
        if (sql_command == SQLCOM_DROP_TABLE) {
7562
 
 
7563
 
                /* MySQL calls this function in DROP Table though this table
7564
 
                handle may belong to another session that is running a query.
7565
 
                Let us in that case skip any changes to the prebuilt struct. */ 
7566
 
 
7567
 
        } else if (lock_type == TL_READ_WITH_SHARED_LOCKS
7568
 
                   || lock_type == TL_READ_NO_INSERT
7569
 
                   || (lock_type != TL_IGNORE
7570
 
                       && sql_command != SQLCOM_SELECT)) {
7571
 
 
7572
 
                /* The OR cases above are in this order:
7573
 
                1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
7574
 
                are processing a stored procedure or function, or
7575
 
                2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
7576
 
                3) this is a SELECT ... IN SHARE MODE, or
7577
 
                4) we are doing a complex SQL statement like
7578
 
                INSERT INTO ... SELECT ... and the logical logging (MySQL
7579
 
                binlog) requires the use of a locking read, or
7580
 
                MySQL is doing LOCK TABLES ... READ.
7581
 
                5) we let InnoDB do locking reads for all SQL statements that
7582
 
                are not simple SELECTs; note that select_lock_type in this
7583
 
                case may get strengthened in ::external_lock() to LOCK_X.
7584
 
                Note that we MUST use a locking read in all data modifying
7585
 
                SQL statements, because otherwise the execution would not be
7586
 
                serializable, and also the results from the update could be
7587
 
                unexpected if an obsolete consistent read view would be
7588
 
                used. */
7589
 
 
7590
 
                ulint   isolation_level;
7591
 
 
7592
 
                isolation_level = trx->isolation_level;
7593
 
 
7594
 
                if ((srv_locks_unsafe_for_binlog
7595
 
                     || isolation_level == TRX_ISO_READ_COMMITTED)
7596
 
                    && isolation_level != TRX_ISO_SERIALIZABLE
7597
 
                    && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
7598
 
                    && (sql_command == SQLCOM_INSERT_SELECT
7599
 
                        || sql_command == SQLCOM_UPDATE
7600
 
                        || sql_command == SQLCOM_CREATE_TABLE)) {
7601
 
 
7602
 
                        /* If we either have innobase_locks_unsafe_for_binlog
7603
 
                        option set or this session is using READ COMMITTED
7604
 
                        isolation level and isolation level of the transaction
7605
 
                        is not set to serializable and MySQL is doing
7606
 
                        INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
7607
 
                        CREATE  ... SELECT... without FOR UPDATE or
7608
 
                        IN SHARE MODE in select, then we use consistent
7609
 
                        read for select. */
7610
 
 
7611
 
                        prebuilt->select_lock_type = LOCK_NONE;
7612
 
                        prebuilt->stored_select_lock_type = LOCK_NONE;
7613
 
                } else if (sql_command == SQLCOM_CHECKSUM) {
7614
 
                        /* Use consistent read for checksum table */
7615
 
 
7616
 
                        prebuilt->select_lock_type = LOCK_NONE;
7617
 
                        prebuilt->stored_select_lock_type = LOCK_NONE;
7618
 
                } else {
7619
 
                        prebuilt->select_lock_type = LOCK_S;
7620
 
                        prebuilt->stored_select_lock_type = LOCK_S;
7621
 
                }
7622
 
 
7623
 
        } else if (lock_type != TL_IGNORE) {
7624
 
 
7625
 
                /* We set possible LOCK_X value in external_lock, not yet
7626
 
                here even if this would be SELECT ... FOR UPDATE */
7627
 
 
7628
 
                prebuilt->select_lock_type = LOCK_NONE;
7629
 
                prebuilt->stored_select_lock_type = LOCK_NONE;
7630
 
        }
7631
 
 
7632
 
        if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
7633
 
 
7634
 
                /* If we are not doing a LOCK TABLE, DISCARD/IMPORT
7635
 
                TABLESPACE or TRUNCATE TABLE then allow multiple
7636
 
                writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
7637
 
                < TL_WRITE_CONCURRENT_INSERT.
7638
 
                */
7639
 
 
7640
 
                if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
7641
 
                     && lock_type <= TL_WRITE)
7642
 
                    && !session_tablespace_op(session)
7643
 
                    && sql_command != SQLCOM_TRUNCATE
7644
 
                    && sql_command != SQLCOM_CREATE_TABLE) {
7645
 
 
7646
 
                        lock_type = TL_WRITE_ALLOW_WRITE;
7647
 
                }
7648
 
 
7649
 
                /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
7650
 
                MySQL would use the lock TL_READ_NO_INSERT on t2, and that
7651
 
                would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
7652
 
                to t2. Convert the lock to a normal read lock to allow
7653
 
                concurrent inserts to t2.
7654
 
    */
7655
 
 
7656
 
                if (lock_type == TL_READ_NO_INSERT) {
7657
 
 
7658
 
                        lock_type = TL_READ;
7659
 
                }
7660
 
 
7661
 
                lock.type = lock_type;
7662
 
        }
7663
 
 
7664
 
        *to++= &lock;
7665
 
 
7666
 
        return(to);
 
7557
  trx_t*    trx;
 
7558
 
 
7559
  /* Note that trx in this function is NOT necessarily prebuilt->trx
 
7560
  because we call update_session() later, in ::external_lock()! Failure to
 
7561
  understand this caused a serious memory corruption bug in 5.1.11. */
 
7562
 
 
7563
  trx = check_trx_exists(session);
 
7564
 
 
7565
  assert(EQ_CURRENT_SESSION(session));
 
7566
  const uint32_t sql_command = session_sql_command(session);
 
7567
 
 
7568
  if (sql_command == SQLCOM_DROP_TABLE) {
 
7569
 
 
7570
    /* MySQL calls this function in DROP Table though this table
 
7571
    handle may belong to another session that is running a query.
 
7572
    Let us in that case skip any changes to the prebuilt struct. */ 
 
7573
 
 
7574
  } else if (lock_type == TL_READ_WITH_SHARED_LOCKS
 
7575
       || lock_type == TL_READ_NO_INSERT
 
7576
       || (lock_type != TL_IGNORE
 
7577
           && sql_command != SQLCOM_SELECT)) {
 
7578
 
 
7579
    /* The OR cases above are in this order:
 
7580
    1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
 
7581
    are processing a stored procedure or function, or
 
7582
    2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
 
7583
    3) this is a SELECT ... IN SHARE MODE, or
 
7584
    4) we are doing a complex SQL statement like
 
7585
    INSERT INTO ... SELECT ... and the logical logging (MySQL
 
7586
    binlog) requires the use of a locking read, or
 
7587
    MySQL is doing LOCK TABLES ... READ.
 
7588
    5) we let InnoDB do locking reads for all SQL statements that
 
7589
    are not simple SELECTs; note that select_lock_type in this
 
7590
    case may get strengthened in ::external_lock() to LOCK_X.
 
7591
    Note that we MUST use a locking read in all data modifying
 
7592
    SQL statements, because otherwise the execution would not be
 
7593
    serializable, and also the results from the update could be
 
7594
    unexpected if an obsolete consistent read view would be
 
7595
    used. */
 
7596
 
 
7597
    ulint isolation_level;
 
7598
 
 
7599
    isolation_level = trx->isolation_level;
 
7600
 
 
7601
    if ((srv_locks_unsafe_for_binlog
 
7602
         || isolation_level == TRX_ISO_READ_COMMITTED)
 
7603
        && isolation_level != TRX_ISO_SERIALIZABLE
 
7604
        && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
 
7605
        && (sql_command == SQLCOM_INSERT_SELECT
 
7606
      || sql_command == SQLCOM_UPDATE
 
7607
      || sql_command == SQLCOM_CREATE_TABLE)) {
 
7608
 
 
7609
      /* If we either have innobase_locks_unsafe_for_binlog
 
7610
      option set or this session is using READ COMMITTED
 
7611
      isolation level and isolation level of the transaction
 
7612
      is not set to serializable and MySQL is doing
 
7613
      INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
 
7614
      CREATE  ... SELECT... without FOR UPDATE or
 
7615
      IN SHARE MODE in select, then we use consistent
 
7616
      read for select. */
 
7617
 
 
7618
      prebuilt->select_lock_type = LOCK_NONE;
 
7619
      prebuilt->stored_select_lock_type = LOCK_NONE;
 
7620
    } else if (sql_command == SQLCOM_CHECKSUM) {
 
7621
      /* Use consistent read for checksum table */
 
7622
 
 
7623
      prebuilt->select_lock_type = LOCK_NONE;
 
7624
      prebuilt->stored_select_lock_type = LOCK_NONE;
 
7625
    } else {
 
7626
      prebuilt->select_lock_type = LOCK_S;
 
7627
      prebuilt->stored_select_lock_type = LOCK_S;
 
7628
    }
 
7629
 
 
7630
  } else if (lock_type != TL_IGNORE) {
 
7631
 
 
7632
    /* We set possible LOCK_X value in external_lock, not yet
 
7633
    here even if this would be SELECT ... FOR UPDATE */
 
7634
 
 
7635
    prebuilt->select_lock_type = LOCK_NONE;
 
7636
    prebuilt->stored_select_lock_type = LOCK_NONE;
 
7637
  }
 
7638
 
 
7639
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
 
7640
 
 
7641
    /* If we are not doing a LOCK TABLE, DISCARD/IMPORT
 
7642
    TABLESPACE or TRUNCATE TABLE then allow multiple
 
7643
    writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
 
7644
    < TL_WRITE_CONCURRENT_INSERT.
 
7645
    */
 
7646
 
 
7647
    if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
 
7648
         && lock_type <= TL_WRITE)
 
7649
        && !session_tablespace_op(session)
 
7650
        && sql_command != SQLCOM_TRUNCATE
 
7651
        && sql_command != SQLCOM_CREATE_TABLE) {
 
7652
 
 
7653
      lock_type = TL_WRITE_ALLOW_WRITE;
 
7654
    }
 
7655
 
 
7656
    /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
 
7657
    MySQL would use the lock TL_READ_NO_INSERT on t2, and that
 
7658
    would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
 
7659
    to t2. Convert the lock to a normal read lock to allow
 
7660
    concurrent inserts to t2.
 
7661
    */
 
7662
 
 
7663
    if (lock_type == TL_READ_NO_INSERT) {
 
7664
 
 
7665
      lock_type = TL_READ;
 
7666
    }
 
7667
 
 
7668
    lock.type = lock_type;
 
7669
  }
 
7670
 
 
7671
  *to++= &lock;
 
7672
 
 
7673
  return(to);
7667
7674
}
7668
7675
 
7669
7676
/*********************************************************************//**
7670
7677
Read the next autoinc value. Acquire the relevant locks before reading
7671
7678
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
7672
7679
on return and all relevant locks acquired.
7673
 
@return DB_SUCCESS or error code */
 
7680
@return DB_SUCCESS or error code */
7674
7681
UNIV_INTERN
7675
7682
ulint
7676
7683
ha_innobase::innobase_get_autoinc(
7677
7684
/*==============================*/
7678
 
        uint64_t*       value)          /*!< out: autoinc value */
 
7685
  uint64_t* value)    /*!< out: autoinc value */
7679
7686
{
7680
 
        *value = 0;
 
7687
  *value = 0;
7681
7688
 
7682
 
        prebuilt->autoinc_error = innobase_lock_autoinc();
7683
 
 
7684
 
        if (prebuilt->autoinc_error == DB_SUCCESS) {
7685
 
 
7686
 
                /* Determine the first value of the interval */
7687
 
                *value = dict_table_autoinc_read(prebuilt->table);
7688
 
 
7689
 
                /* It should have been initialized during open. */
7690
 
                ut_a(*value != 0);
7691
 
        }
7692
 
 
7693
 
        return(prebuilt->autoinc_error);
 
7689
  prebuilt->autoinc_error = innobase_lock_autoinc();
 
7690
 
 
7691
  if (prebuilt->autoinc_error == DB_SUCCESS) {
 
7692
 
 
7693
    /* Determine the first value of the interval */
 
7694
    *value = dict_table_autoinc_read(prebuilt->table);
 
7695
 
 
7696
    /* It should have been initialized during open. */
 
7697
    ut_a(*value != 0);
 
7698
  }
 
7699
 
 
7700
  return(prebuilt->autoinc_error);
7694
7701
}
7695
7702
 
7696
7703
/*******************************************************************//**
7697
7704
This function reads the global auto-inc counter. It doesn't use the 
7698
7705
AUTOINC lock even if the lock mode is set to TRADITIONAL.
7699
 
@return the autoinc value */
 
7706
@return the autoinc value */
7700
7707
UNIV_INTERN
7701
7708
uint64_t
7702
7709
ha_innobase::innobase_peek_autoinc(void)
7703
7710
/*====================================*/
7704
7711
{
7705
 
        uint64_t        auto_inc;
7706
 
        dict_table_t*   innodb_table;
7707
 
 
7708
 
        ut_a(prebuilt != NULL);
7709
 
        ut_a(prebuilt->table != NULL);
7710
 
 
7711
 
        innodb_table = prebuilt->table;
7712
 
 
7713
 
        dict_table_autoinc_lock(innodb_table);
7714
 
 
7715
 
        auto_inc = dict_table_autoinc_read(innodb_table);
7716
 
 
7717
 
        ut_a(auto_inc > 0);
7718
 
 
7719
 
        dict_table_autoinc_unlock(innodb_table);
7720
 
 
7721
 
        return(auto_inc);
 
7712
  uint64_t  auto_inc;
 
7713
  dict_table_t* innodb_table;
 
7714
 
 
7715
  ut_a(prebuilt != NULL);
 
7716
  ut_a(prebuilt->table != NULL);
 
7717
 
 
7718
  innodb_table = prebuilt->table;
 
7719
 
 
7720
  dict_table_autoinc_lock(innodb_table);
 
7721
 
 
7722
  auto_inc = dict_table_autoinc_read(innodb_table);
 
7723
 
 
7724
  ut_a(auto_inc > 0);
 
7725
 
 
7726
  dict_table_autoinc_unlock(innodb_table);
 
7727
 
 
7728
  return(auto_inc);
7722
7729
}
7723
7730
 
7724
7731
/*********************************************************************//**
7732
7739
void
7733
7740
ha_innobase::get_auto_increment(
7734
7741
/*============================*/
7735
 
        uint64_t        offset,              /*!< in: table autoinc offset */
7736
 
        uint64_t        increment,           /*!< in: table autoinc increment */
7737
 
        uint64_t        nb_desired_values,   /*!< in: number of values reqd */
7738
 
        uint64_t        *first_value,        /*!< out: the autoinc value */
7739
 
        uint64_t        *nb_reserved_values) /*!< out: count of reserved values */
 
7742
        uint64_t  offset,              /*!< in: table autoinc offset */
 
7743
        uint64_t  increment,           /*!< in: table autoinc increment */
 
7744
        uint64_t  nb_desired_values,   /*!< in: number of values reqd */
 
7745
        uint64_t  *first_value,        /*!< out: the autoinc value */
 
7746
        uint64_t  *nb_reserved_values) /*!< out: count of reserved values */
7740
7747
{
7741
 
        trx_t*          trx;
7742
 
        ulint           error;
7743
 
        uint64_t        autoinc = 0;
7744
 
 
7745
 
        /* Prepare prebuilt->trx in the table handle */
7746
 
        update_session(ha_session());
7747
 
 
7748
 
        error = innobase_get_autoinc(&autoinc);
7749
 
 
7750
 
        if (error != DB_SUCCESS) {
7751
 
                *first_value = (~(uint64_t) 0);
7752
 
                return;
7753
 
        }
7754
 
 
7755
 
        /* This is a hack, since nb_desired_values seems to be accurate only
7756
 
        for the first call to get_auto_increment() for multi-row INSERT and
7757
 
        meaningless for other statements e.g, LOAD etc. Subsequent calls to
7758
 
        this method for the same statement results in different values which
7759
 
        don't make sense. Therefore we store the value the first time we are
7760
 
        called and count down from that as rows are written (see write_row()).
7761
 
        */
7762
 
 
7763
 
        trx = prebuilt->trx;
7764
 
 
7765
 
        /* Note: We can't rely on *first_value since some MySQL engines,
7766
 
        in particular the partition engine, don't initialize it to 0 when
7767
 
        invoking this method. So we are not sure if it's guaranteed to
7768
 
        be 0 or not. */
7769
 
 
7770
 
        /* Called for the first time ? */
7771
 
        if (trx->n_autoinc_rows == 0) {
7772
 
 
7773
 
                trx->n_autoinc_rows = (ulint) nb_desired_values;
7774
 
 
7775
 
                /* It's possible for nb_desired_values to be 0:
7776
 
                e.g., INSERT INTO T1(C) SELECT C FROM T2; */
7777
 
                if (nb_desired_values == 0) {
7778
 
 
7779
 
                        trx->n_autoinc_rows = 1;
7780
 
                }
7781
 
 
7782
 
                set_if_bigger(*first_value, autoinc);
7783
 
        /* Not in the middle of a mult-row INSERT. */
7784
 
        } else if (prebuilt->autoinc_last_value == 0) {
7785
 
                set_if_bigger(*first_value, autoinc);
7786
 
        }
7787
 
 
7788
 
        *nb_reserved_values = trx->n_autoinc_rows;
7789
 
 
7790
 
        /* With old style AUTOINC locking we only update the table's
7791
 
        AUTOINC counter after attempting to insert the row. */
7792
 
        if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
7793
 
                uint64_t        need;
7794
 
                uint64_t        next_value;
7795
 
                uint64_t        col_max_value;
7796
 
 
7797
 
                /* We need the upper limit of the col type to check for
7798
 
                whether we update the table autoinc counter or not. */
7799
 
                col_max_value = innobase_get_int_col_max_value(
7800
 
                        table->next_number_field);
7801
 
 
7802
 
                need = *nb_reserved_values * increment;
7803
 
 
7804
 
                /* Compute the last value in the interval */
7805
 
                next_value = innobase_next_autoinc(
7806
 
                        *first_value, need, offset, col_max_value);
7807
 
 
7808
 
                prebuilt->autoinc_last_value = next_value;
7809
 
 
7810
 
                if (prebuilt->autoinc_last_value < *first_value) {
7811
 
                        *first_value = (~(unsigned long long) 0);
7812
 
                } else {
7813
 
                        /* Update the table autoinc variable */
7814
 
                        dict_table_autoinc_update_if_greater(
7815
 
                                prebuilt->table, prebuilt->autoinc_last_value);
7816
 
                }
7817
 
        } else {
7818
 
                /* This will force write_row() into attempting an update
7819
 
                of the table's AUTOINC counter. */
7820
 
                prebuilt->autoinc_last_value = 0;
7821
 
        }
7822
 
 
7823
 
        /* The increment to be used to increase the AUTOINC value, we use
7824
 
        this in write_row() and update_row() to increase the autoinc counter
7825
 
        for columns that are filled by the user. We need the offset and
7826
 
        the increment. */
7827
 
        prebuilt->autoinc_offset = offset;
7828
 
        prebuilt->autoinc_increment = increment;
7829
 
 
7830
 
        dict_table_autoinc_unlock(prebuilt->table);
 
7748
  trx_t*    trx;
 
7749
  ulint   error;
 
7750
  uint64_t  autoinc = 0;
 
7751
 
 
7752
  /* Prepare prebuilt->trx in the table handle */
 
7753
  update_session(ha_session());
 
7754
 
 
7755
  error = innobase_get_autoinc(&autoinc);
 
7756
 
 
7757
  if (error != DB_SUCCESS) {
 
7758
    *first_value = (~(uint64_t) 0);
 
7759
    return;
 
7760
  }
 
7761
 
 
7762
  /* This is a hack, since nb_desired_values seems to be accurate only
 
7763
  for the first call to get_auto_increment() for multi-row INSERT and
 
7764
  meaningless for other statements e.g, LOAD etc. Subsequent calls to
 
7765
  this method for the same statement results in different values which
 
7766
  don't make sense. Therefore we store the value the first time we are
 
7767
  called and count down from that as rows are written (see write_row()).
 
7768
  */
 
7769
 
 
7770
  trx = prebuilt->trx;
 
7771
 
 
7772
  /* Note: We can't rely on *first_value since some MySQL engines,
 
7773
  in particular the partition engine, don't initialize it to 0 when
 
7774
  invoking this method. So we are not sure if it's guaranteed to
 
7775
  be 0 or not. */
 
7776
 
 
7777
  /* Called for the first time ? */
 
7778
  if (trx->n_autoinc_rows == 0) {
 
7779
 
 
7780
    trx->n_autoinc_rows = (ulint) nb_desired_values;
 
7781
 
 
7782
    /* It's possible for nb_desired_values to be 0:
 
7783
    e.g., INSERT INTO T1(C) SELECT C FROM T2; */
 
7784
    if (nb_desired_values == 0) {
 
7785
 
 
7786
      trx->n_autoinc_rows = 1;
 
7787
    }
 
7788
 
 
7789
    set_if_bigger(*first_value, autoinc);
 
7790
  /* Not in the middle of a mult-row INSERT. */
 
7791
  } else if (prebuilt->autoinc_last_value == 0) {
 
7792
    set_if_bigger(*first_value, autoinc);
 
7793
  }
 
7794
 
 
7795
  *nb_reserved_values = trx->n_autoinc_rows;
 
7796
 
 
7797
  /* With old style AUTOINC locking we only update the table's
 
7798
  AUTOINC counter after attempting to insert the row. */
 
7799
  if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
 
7800
    uint64_t  need;
 
7801
    uint64_t  next_value;
 
7802
    uint64_t  col_max_value;
 
7803
 
 
7804
    /* We need the upper limit of the col type to check for
 
7805
    whether we update the table autoinc counter or not. */
 
7806
    col_max_value = innobase_get_int_col_max_value(
 
7807
      table->next_number_field);
 
7808
 
 
7809
    need = *nb_reserved_values * increment;
 
7810
 
 
7811
    /* Compute the last value in the interval */
 
7812
    next_value = innobase_next_autoinc(
 
7813
      *first_value, need, offset, col_max_value);
 
7814
 
 
7815
    prebuilt->autoinc_last_value = next_value;
 
7816
 
 
7817
    if (prebuilt->autoinc_last_value < *first_value) {
 
7818
      *first_value = (~(unsigned long long) 0);
 
7819
    } else {
 
7820
      /* Update the table autoinc variable */
 
7821
      dict_table_autoinc_update_if_greater(
 
7822
        prebuilt->table, prebuilt->autoinc_last_value);
 
7823
    }
 
7824
  } else {
 
7825
    /* This will force write_row() into attempting an update
 
7826
    of the table's AUTOINC counter. */
 
7827
    prebuilt->autoinc_last_value = 0;
 
7828
  }
 
7829
 
 
7830
  /* The increment to be used to increase the AUTOINC value, we use
 
7831
  this in write_row() and update_row() to increase the autoinc counter
 
7832
  for columns that are filled by the user. We need the offset and
 
7833
  the increment. */
 
7834
  prebuilt->autoinc_offset = offset;
 
7835
  prebuilt->autoinc_increment = increment;
 
7836
 
 
7837
  dict_table_autoinc_unlock(prebuilt->table);
7831
7838
}
7832
7839
 
7833
7840
/*******************************************************************//**
7835
7842
inserted will get the given value. This is called e.g. after TRUNCATE
7836
7843
is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
7837
7844
returned by storage engines that don't support this operation.
7838
 
@return 0 or error code */
 
7845
@return 0 or error code */
7839
7846
UNIV_INTERN
7840
7847
int
7841
7848
ha_innobase::reset_auto_increment(
7842
7849
/*==============================*/
7843
 
        uint64_t        value)          /*!< in: new value for table autoinc */
 
7850
  uint64_t  value)    /*!< in: new value for table autoinc */
7844
7851
{
7845
 
        int     error;
7846
 
 
7847
 
        update_session(ha_session());
7848
 
 
7849
 
        error = row_lock_table_autoinc_for_mysql(prebuilt);
7850
 
 
7851
 
        if (error != DB_SUCCESS) {
7852
 
                error = convert_error_code_to_mysql(error,
7853
 
                                                    prebuilt->table->flags,
7854
 
                                                    user_session);
7855
 
 
7856
 
                return(error);
7857
 
        }
7858
 
 
7859
 
        /* The next value can never be 0. */
7860
 
        if (value == 0) {
7861
 
                value = 1;
7862
 
        }
7863
 
 
7864
 
        innobase_reset_autoinc(value);
7865
 
 
7866
 
        return 0;
 
7852
  int error;
 
7853
 
 
7854
  update_session(ha_session());
 
7855
 
 
7856
  error = row_lock_table_autoinc_for_mysql(prebuilt);
 
7857
 
 
7858
  if (error != DB_SUCCESS) {
 
7859
    error = convert_error_code_to_mysql(error,
 
7860
                prebuilt->table->flags,
 
7861
                user_session);
 
7862
 
 
7863
    return(error);
 
7864
  }
 
7865
 
 
7866
  /* The next value can never be 0. */
 
7867
  if (value == 0) {
 
7868
    value = 1;
 
7869
  }
 
7870
 
 
7871
  innobase_reset_autoinc(value);
 
7872
 
 
7873
  return 0;
7867
7874
}
7868
7875
 
7869
7876
/* See comment in Cursor.cc */
7871
7878
bool
7872
7879
InnobaseEngine::get_error_message(int, String *buf)
7873
7880
{
7874
 
        trx_t*  trx = check_trx_exists(current_session);
7875
 
 
7876
 
        buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
7877
 
                system_charset_info);
7878
 
 
7879
 
        return(FALSE);
 
7881
  trx_t*  trx = check_trx_exists(current_session);
 
7882
 
 
7883
  buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
 
7884
    system_charset_info);
 
7885
 
 
7886
  return(FALSE);
7880
7887
}
7881
7888
 
7882
7889
/*******************************************************************//**
7883
7890
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
7884
7891
If there is no explicitly declared non-null unique key or a primary key, then
7885
7892
InnoDB internally uses the row id as the primary key.
7886
 
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
 
7893
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
7887
7894
UNIV_INTERN
7888
7895
int
7889
7896
ha_innobase::cmp_ref(
7890
7897
/*=================*/
7891
 
        const unsigned char*    ref1,   /*!< in: an (internal) primary key value in the
7892
 
                                MySQL key value format */
7893
 
        const unsigned char*    ref2)   /*!< in: an (internal) primary key value in the
7894
 
                                MySQL key value format */
 
7898
  const unsigned char*  ref1, /*!< in: an (internal) primary key value in the
 
7899
        MySQL key value format */
 
7900
  const unsigned char*  ref2) /*!< in: an (internal) primary key value in the
 
7901
        MySQL key value format */
7895
7902
{
7896
 
        enum_field_types mysql_type;
7897
 
        Field*          field;
7898
 
        KEY_PART_INFO*  key_part;
7899
 
        KEY_PART_INFO*  key_part_end;
7900
 
        uint            len1;
7901
 
        uint            len2;
7902
 
        int             result;
7903
 
 
7904
 
        if (prebuilt->clust_index_was_generated) {
7905
 
                /* The 'ref' is an InnoDB row id */
7906
 
 
7907
 
                return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
7908
 
        }
7909
 
 
7910
 
        /* Do a type-aware comparison of primary key fields. PK fields
7911
 
        are always NOT NULL, so no checks for NULL are performed. */
7912
 
 
7913
 
        key_part = table->key_info[table->s->primary_key].key_part;
7914
 
 
7915
 
        key_part_end = key_part
7916
 
                        + table->key_info[table->s->primary_key].key_parts;
7917
 
 
7918
 
        for (; key_part != key_part_end; ++key_part) {
7919
 
                field = key_part->field;
7920
 
                mysql_type = field->type();
7921
 
 
7922
 
                if (mysql_type == DRIZZLE_TYPE_BLOB) {
7923
 
 
7924
 
                        /* In the MySQL key value format, a column prefix of
7925
 
                        a BLOB is preceded by a 2-byte length field */
7926
 
 
7927
 
                        len1 = innobase_read_from_2_little_endian(ref1);
7928
 
                        len2 = innobase_read_from_2_little_endian(ref2);
7929
 
 
7930
 
                        ref1 += 2;
7931
 
                        ref2 += 2;
7932
 
                        result = ((Field_blob*)field)->cmp( ref1, len1,
 
7903
  enum_field_types mysql_type;
 
7904
  Field*    field;
 
7905
  KEY_PART_INFO*  key_part;
 
7906
  KEY_PART_INFO*  key_part_end;
 
7907
  uint    len1;
 
7908
  uint    len2;
 
7909
  int   result;
 
7910
 
 
7911
  if (prebuilt->clust_index_was_generated) {
 
7912
    /* The 'ref' is an InnoDB row id */
 
7913
 
 
7914
    return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
 
7915
  }
 
7916
 
 
7917
  /* Do a type-aware comparison of primary key fields. PK fields
 
7918
  are always NOT NULL, so no checks for NULL are performed. */
 
7919
 
 
7920
  key_part = table->key_info[table->s->primary_key].key_part;
 
7921
 
 
7922
  key_part_end = key_part
 
7923
      + table->key_info[table->s->primary_key].key_parts;
 
7924
 
 
7925
  for (; key_part != key_part_end; ++key_part) {
 
7926
    field = key_part->field;
 
7927
    mysql_type = field->type();
 
7928
 
 
7929
    if (mysql_type == DRIZZLE_TYPE_BLOB) {
 
7930
 
 
7931
      /* In the MySQL key value format, a column prefix of
 
7932
      a BLOB is preceded by a 2-byte length field */
 
7933
 
 
7934
      len1 = innobase_read_from_2_little_endian(ref1);
 
7935
      len2 = innobase_read_from_2_little_endian(ref2);
 
7936
 
 
7937
      ref1 += 2;
 
7938
      ref2 += 2;
 
7939
      result = ((Field_blob*)field)->cmp( ref1, len1,
7933
7940
                                                            ref2, len2);
7934
 
                } else {
7935
 
                        result = field->key_cmp(ref1, ref2);
7936
 
                }
7937
 
 
7938
 
                if (result) {
7939
 
 
7940
 
                        return(result);
7941
 
                }
7942
 
 
7943
 
                ref1 += key_part->store_length;
7944
 
                ref2 += key_part->store_length;
7945
 
        }
7946
 
 
7947
 
        return(0);
 
7941
    } else {
 
7942
      result = field->key_cmp(ref1, ref2);
 
7943
    }
 
7944
 
 
7945
    if (result) {
 
7946
 
 
7947
      return(result);
 
7948
    }
 
7949
 
 
7950
    ref1 += key_part->store_length;
 
7951
    ref2 += key_part->store_length;
 
7952
  }
 
7953
 
 
7954
  return(0);
7948
7955
}
7949
7956
 
7950
7957
/**********************************************************************
7952
7959
characters for prefix indexes using a multibyte character set. The function
7953
7960
finds charset information and returns length of prefix_len characters in the
7954
7961
index field in bytes.
7955
 
@return number of bytes occupied by the first n characters */
 
7962
@return number of bytes occupied by the first n characters */
7956
7963
extern "C" UNIV_INTERN
7957
7964
ulint
7958
7965
innobase_get_at_most_n_mbchars(
7959
7966
/*===========================*/
7960
 
        ulint charset_id,       /*!< in: character set id */
7961
 
        ulint prefix_len,       /*!< in: prefix length in bytes of the index
7962
 
                                (this has to be divided by mbmaxlen to get the
7963
 
                                number of CHARACTERS n in the prefix) */
7964
 
        ulint data_len,         /*!< in: length of the string in bytes */
7965
 
        const char* str);       /*!< in: character string */
 
7967
  ulint charset_id, /*!< in: character set id */
 
7968
  ulint prefix_len, /*!< in: prefix length in bytes of the index
 
7969
        (this has to be divided by mbmaxlen to get the
 
7970
        number of CHARACTERS n in the prefix) */
 
7971
  ulint data_len,   /*!< in: length of the string in bytes */
 
7972
  const char* str); /*!< in: character string */
7966
7973
 
7967
7974
ulint
7968
7975
innobase_get_at_most_n_mbchars(
7969
7976
/*===========================*/
7970
 
        ulint charset_id,       /*!< in: character set id */
7971
 
        ulint prefix_len,       /*!< in: prefix length in bytes of the index
7972
 
                                (this has to be divided by mbmaxlen to get the
7973
 
                                number of CHARACTERS n in the prefix) */
7974
 
        ulint data_len,         /*!< in: length of the string in bytes */
7975
 
        const char* str)        /*!< in: character string */
 
7977
  ulint charset_id, /*!< in: character set id */
 
7978
  ulint prefix_len, /*!< in: prefix length in bytes of the index
 
7979
        (this has to be divided by mbmaxlen to get the
 
7980
        number of CHARACTERS n in the prefix) */
 
7981
  ulint data_len,   /*!< in: length of the string in bytes */
 
7982
  const char* str)  /*!< in: character string */
7976
7983
{
7977
 
        ulint char_length;              /*!< character length in bytes */
7978
 
        ulint n_chars;                  /*!< number of characters in prefix */
7979
 
        const CHARSET_INFO* charset;    /*!< charset used in the field */
7980
 
 
7981
 
        charset = get_charset((uint) charset_id);
7982
 
 
7983
 
        ut_ad(charset);
7984
 
        ut_ad(charset->mbmaxlen);
7985
 
 
7986
 
        /* Calculate how many characters at most the prefix index contains */
7987
 
 
7988
 
        n_chars = prefix_len / charset->mbmaxlen;
7989
 
 
7990
 
        /* If the charset is multi-byte, then we must find the length of the
7991
 
        first at most n chars in the string. If the string contains less
7992
 
        characters than n, then we return the length to the end of the last
7993
 
        character. */
7994
 
 
7995
 
        if (charset->mbmaxlen > 1) {
7996
 
                /* my_charpos() returns the byte length of the first n_chars
7997
 
                characters, or a value bigger than the length of str, if
7998
 
                there were not enough full characters in str.
7999
 
 
8000
 
                Why does the code below work:
8001
 
                Suppose that we are looking for n UTF-8 characters.
8002
 
 
8003
 
                1) If the string is long enough, then the prefix contains at
8004
 
                least n complete UTF-8 characters + maybe some extra
8005
 
                characters + an incomplete UTF-8 character. No problem in
8006
 
                this case. The function returns the pointer to the
8007
 
                end of the nth character.
8008
 
 
8009
 
                2) If the string is not long enough, then the string contains
8010
 
                the complete value of a column, that is, only complete UTF-8
8011
 
                characters, and we can store in the column prefix index the
8012
 
                whole string. */
8013
 
 
8014
 
                char_length = my_charpos(charset, str,
8015
 
                                                str + data_len, (int) n_chars);
8016
 
                if (char_length > data_len) {
8017
 
                        char_length = data_len;
8018
 
                }
8019
 
        } else {
8020
 
                if (data_len < prefix_len) {
8021
 
                        char_length = data_len;
8022
 
                } else {
8023
 
                        char_length = prefix_len;
8024
 
                }
8025
 
        }
8026
 
 
8027
 
        return(char_length);
 
7984
  ulint char_length;    /*!< character length in bytes */
 
7985
  ulint n_chars;      /*!< number of characters in prefix */
 
7986
  const CHARSET_INFO* charset;  /*!< charset used in the field */
 
7987
 
 
7988
  charset = get_charset((uint) charset_id);
 
7989
 
 
7990
  ut_ad(charset);
 
7991
  ut_ad(charset->mbmaxlen);
 
7992
 
 
7993
  /* Calculate how many characters at most the prefix index contains */
 
7994
 
 
7995
  n_chars = prefix_len / charset->mbmaxlen;
 
7996
 
 
7997
  /* If the charset is multi-byte, then we must find the length of the
 
7998
  first at most n chars in the string. If the string contains less
 
7999
  characters than n, then we return the length to the end of the last
 
8000
  character. */
 
8001
 
 
8002
  if (charset->mbmaxlen > 1) {
 
8003
    /* my_charpos() returns the byte length of the first n_chars
 
8004
    characters, or a value bigger than the length of str, if
 
8005
    there were not enough full characters in str.
 
8006
 
 
8007
    Why does the code below work:
 
8008
    Suppose that we are looking for n UTF-8 characters.
 
8009
 
 
8010
    1) If the string is long enough, then the prefix contains at
 
8011
    least n complete UTF-8 characters + maybe some extra
 
8012
    characters + an incomplete UTF-8 character. No problem in
 
8013
    this case. The function returns the pointer to the
 
8014
    end of the nth character.
 
8015
 
 
8016
    2) If the string is not long enough, then the string contains
 
8017
    the complete value of a column, that is, only complete UTF-8
 
8018
    characters, and we can store in the column prefix index the
 
8019
    whole string. */
 
8020
 
 
8021
    char_length = my_charpos(charset, str,
 
8022
            str + data_len, (int) n_chars);
 
8023
    if (char_length > data_len) {
 
8024
      char_length = data_len;
 
8025
    }
 
8026
  } else {
 
8027
    if (data_len < prefix_len) {
 
8028
      char_length = data_len;
 
8029
    } else {
 
8030
      char_length = prefix_len;
 
8031
    }
 
8032
  }
 
8033
 
 
8034
  return(char_length);
8028
8035
}
8029
8036
/**
8030
8037
 * We will also use this function to communicate
8034
8041
 */
8035
8042
void
8036
8043
InnobaseEngine::doStartStatement(
8037
 
        Session *session) /*!< in: handle to the Drizzle session */
 
8044
  Session *session) /*!< in: handle to the Drizzle session */
8038
8045
{
8039
8046
  /* 
8040
8047
   * Create the InnoDB transaction structure
8041
8048
   * for the session
8042
8049
   */
8043
 
        trx_t *trx= check_trx_exists(session);
 
8050
  trx_t *trx= check_trx_exists(session);
8044
8051
 
8045
8052
  /* "reset" the error message for the transaction */
8046
8053
  trx->detailed_error[0]= '\0';
8047
8054
 
8048
 
        /* Set the isolation level of the transaction. */
 
8055
  /* Set the isolation level of the transaction. */
8049
8056
  trx->isolation_level= innobase_map_isolation_level((enum_tx_isolation) session_tx_isolation(session));
8050
8057
}
8051
8058
 
8082
8089
 
8083
8090
/*******************************************************************//**
8084
8091
This function is used to prepare an X/Open XA distributed transaction.
8085
 
@return 0 or error number */
 
8092
@return 0 or error number */
8086
8093
int
8087
8094
InnobaseEngine::doXaPrepare(
8088
8095
/*================*/
8089
 
        Session*        session,/*!< in: handle to the MySQL thread of
8090
 
                                the user whose XA transaction should
8091
 
                                be prepared */
8092
 
        bool            all)    /*!< in: TRUE - commit transaction
8093
 
                                FALSE - the current SQL statement
8094
 
                                ended */
 
8096
  Session*  session,/*!< in: handle to the MySQL thread of
 
8097
        the user whose XA transaction should
 
8098
        be prepared */
 
8099
  bool    all)  /*!< in: TRUE - commit transaction
 
8100
        FALSE - the current SQL statement
 
8101
        ended */
8095
8102
{
8096
 
        int error = 0;
8097
 
        trx_t* trx = check_trx_exists(session);
8098
 
 
8099
 
        assert(this == innodb_engine_ptr);
8100
 
 
8101
 
        /* we use support_xa value as it was seen at transaction start
8102
 
        time, not the current session variable value. Any possible changes
8103
 
        to the session variable take effect only in the next transaction */
8104
 
        if (!trx->support_xa) {
8105
 
 
8106
 
                return(0);
8107
 
        }
8108
 
 
8109
 
        session_get_xid(session, reinterpret_cast<DRIZZLE_XID*>(&trx->xid));
8110
 
 
8111
 
        /* Release a possible FIFO ticket and search latch. Since we will
8112
 
        reserve the kernel mutex, we have to release the search system latch
8113
 
        first to obey the latching order. */
8114
 
 
8115
 
        innobase_release_stat_resources(trx);
8116
 
 
8117
 
        if (all
8118
 
                || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
8119
 
 
8120
 
                /* We were instructed to prepare the whole transaction, or
8121
 
                this is an SQL statement end and autocommit is on */
8122
 
 
8123
 
                ut_ad(trx->conc_state != TRX_NOT_STARTED);
8124
 
 
8125
 
                error = (int) trx_prepare_for_mysql(trx);
8126
 
        } else {
8127
 
                /* We just mark the SQL statement ended and do not do a
8128
 
                transaction prepare */
8129
 
 
8130
 
                /* If we had reserved the auto-inc lock for some
8131
 
                table in this SQL statement we release it now */
8132
 
 
8133
 
                row_unlock_table_autoinc_for_mysql(trx);
8134
 
 
8135
 
                /* Store the current undo_no of the transaction so that we
8136
 
                know where to roll back if we have to roll back the next
8137
 
                SQL statement */
8138
 
 
8139
 
                trx_mark_sql_stat_end(trx);
8140
 
        }
8141
 
 
8142
 
        /* Tell the InnoDB server that there might be work for utility
8143
 
        threads: */
8144
 
 
8145
 
        srv_active_wake_master_thread();
8146
 
 
8147
 
        return(error);
 
8103
  int error = 0;
 
8104
  trx_t* trx = check_trx_exists(session);
 
8105
 
 
8106
  assert(this == innodb_engine_ptr);
 
8107
 
 
8108
  /* we use support_xa value as it was seen at transaction start
 
8109
  time, not the current session variable value. Any possible changes
 
8110
  to the session variable take effect only in the next transaction */
 
8111
  if (!trx->support_xa) {
 
8112
 
 
8113
    return(0);
 
8114
  }
 
8115
 
 
8116
  session_get_xid(session, reinterpret_cast<DRIZZLE_XID*>(&trx->xid));
 
8117
 
 
8118
  /* Release a possible FIFO ticket and search latch. Since we will
 
8119
  reserve the kernel mutex, we have to release the search system latch
 
8120
  first to obey the latching order. */
 
8121
 
 
8122
  innobase_release_stat_resources(trx);
 
8123
 
 
8124
  if (all
 
8125
    || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
 
8126
 
 
8127
    /* We were instructed to prepare the whole transaction, or
 
8128
    this is an SQL statement end and autocommit is on */
 
8129
 
 
8130
    ut_ad(trx->conc_state != TRX_NOT_STARTED);
 
8131
 
 
8132
    error = (int) trx_prepare_for_mysql(trx);
 
8133
  } else {
 
8134
    /* We just mark the SQL statement ended and do not do a
 
8135
    transaction prepare */
 
8136
 
 
8137
    /* If we had reserved the auto-inc lock for some
 
8138
    table in this SQL statement we release it now */
 
8139
 
 
8140
    row_unlock_table_autoinc_for_mysql(trx);
 
8141
 
 
8142
    /* Store the current undo_no of the transaction so that we
 
8143
    know where to roll back if we have to roll back the next
 
8144
    SQL statement */
 
8145
 
 
8146
    trx_mark_sql_stat_end(trx);
 
8147
  }
 
8148
 
 
8149
  /* Tell the InnoDB server that there might be work for utility
 
8150
  threads: */
 
8151
 
 
8152
  srv_active_wake_master_thread();
 
8153
 
 
8154
  return(error);
8148
8155
}
8149
8156
 
8150
8157
/*******************************************************************//**
8151
8158
This function is used to recover X/Open XA distributed transactions.
8152
 
@return number of prepared transactions stored in xid_list */
 
8159
@return number of prepared transactions stored in xid_list */
8153
8160
int
8154
8161
InnobaseEngine::doXaRecover(
8155
8162
/*================*/
8156
 
        ::drizzled::XID*        xid_list,/*!< in/out: prepared transactions */
8157
 
        size_t len)     /*!< in: number of slots in xid_list */
 
8163
  ::drizzled::XID*  xid_list,/*!< in/out: prepared transactions */
 
8164
  size_t len) /*!< in: number of slots in xid_list */
8158
8165
{
8159
 
        assert(this == innodb_engine_ptr);
8160
 
 
8161
 
        if (len == 0 || xid_list == NULL) {
8162
 
 
8163
 
                return(0);
8164
 
        }
8165
 
 
8166
 
        return(trx_recover_for_mysql((::XID *)xid_list, len));
 
8166
  assert(this == innodb_engine_ptr);
 
8167
 
 
8168
  if (len == 0 || xid_list == NULL) {
 
8169
 
 
8170
    return(0);
 
8171
  }
 
8172
 
 
8173
  return(trx_recover_for_mysql((::XID *)xid_list, len));
8167
8174
}
8168
8175
 
8169
8176
/*******************************************************************//**
8170
8177
This function is used to commit one X/Open XA distributed transaction
8171
8178
which is in the prepared state
8172
 
@return 0 or error number */
 
8179
@return 0 or error number */
8173
8180
int
8174
8181
InnobaseEngine::doXaCommitXid(
8175
8182
/*===================*/
8176
 
        ::drizzled::XID*        xid)    /*!< in: X/Open XA transaction identification */
 
8183
  ::drizzled::XID*  xid)  /*!< in: X/Open XA transaction identification */
8177
8184
{
8178
 
        trx_t*  trx;
8179
 
 
8180
 
        assert(this == innodb_engine_ptr);
8181
 
 
8182
 
        trx = trx_get_trx_by_xid((::XID *)xid);
8183
 
 
8184
 
        if (trx) {
8185
 
                innobase_commit_low(trx);
8186
 
 
8187
 
                return(XA_OK);
8188
 
        } else {
8189
 
                return(XAER_NOTA);
8190
 
        }
 
8185
  trx_t*  trx;
 
8186
 
 
8187
  assert(this == innodb_engine_ptr);
 
8188
 
 
8189
  trx = trx_get_trx_by_xid((::XID *)xid);
 
8190
 
 
8191
  if (trx) {
 
8192
    innobase_commit_low(trx);
 
8193
 
 
8194
    return(XA_OK);
 
8195
  } else {
 
8196
    return(XAER_NOTA);
 
8197
  }
8191
8198
}
8192
8199
 
8193
8200
/*******************************************************************//**
8194
8201
This function is used to rollback one X/Open XA distributed transaction
8195
8202
which is in the prepared state
8196
 
@return 0 or error number */
 
8203
@return 0 or error number */
8197
8204
int
8198
8205
InnobaseEngine::doXaRollbackXid(
8199
8206
/*=====================*/
8200
 
        ::drizzled::XID*                xid)    /*!< in: X/Open XA transaction
8201
 
                                identification */
 
8207
  ::drizzled::XID*    xid)  /*!< in: X/Open XA transaction
 
8208
        identification */
8202
8209
{
8203
 
        trx_t*  trx;
8204
 
 
8205
 
        assert(this == innodb_engine_ptr);
8206
 
 
8207
 
        trx = trx_get_trx_by_xid((::XID *)xid);
8208
 
 
8209
 
        if (trx) {
8210
 
                return(innobase_rollback_trx(trx));
8211
 
        } else {
8212
 
                return(XAER_NOTA);
8213
 
        }
 
8210
  trx_t*  trx;
 
8211
 
 
8212
  assert(this == innodb_engine_ptr);
 
8213
 
 
8214
  trx = trx_get_trx_by_xid((::XID *)xid);
 
8215
 
 
8216
  if (trx) {
 
8217
    return(innobase_rollback_trx(trx));
 
8218
  } else {
 
8219
    return(XAER_NOTA);
 
8220
  }
8214
8221
}
8215
8222
 
8216
8223
 
8217
8224
/************************************************************//**
8218
8225
Validate the file format name and return its corresponding id.
8219
 
@return valid file format id */
 
8226
@return valid file format id */
8220
8227
static
8221
8228
uint
8222
8229
innobase_file_format_name_lookup(
8223
8230
/*=============================*/
8224
 
        const char*     format_name)    /*!< in: pointer to file format name */
 
8231
  const char* format_name)  /*!< in: pointer to file format name */
8225
8232
{
8226
 
        char*   endp;
8227
 
        uint    format_id;
8228
 
 
8229
 
        ut_a(format_name != NULL);
8230
 
 
8231
 
        /* The format name can contain the format id itself instead of
8232
 
        the name and we check for that. */
8233
 
        format_id = (uint) strtoul(format_name, &endp, 10);
8234
 
 
8235
 
        /* Check for valid parse. */
8236
 
        if (*endp == '\0' && *format_name != '\0') {
8237
 
 
8238
 
                if (format_id <= DICT_TF_FORMAT_MAX) {
8239
 
 
8240
 
                        return(format_id);
8241
 
                }
8242
 
        } else {
8243
 
 
8244
 
                for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
8245
 
                     format_id++) {
8246
 
                        const char*     name;
8247
 
 
8248
 
                        name = trx_sys_file_format_id_to_name(format_id);
8249
 
 
8250
 
                        if (!innobase_strcasecmp(format_name, name)) {
8251
 
 
8252
 
                                return(format_id);
8253
 
                        }
8254
 
                }
8255
 
        }
8256
 
 
8257
 
        return(DICT_TF_FORMAT_MAX + 1);
 
8233
  char* endp;
 
8234
  uint  format_id;
 
8235
 
 
8236
  ut_a(format_name != NULL);
 
8237
 
 
8238
  /* The format name can contain the format id itself instead of
 
8239
  the name and we check for that. */
 
8240
  format_id = (uint) strtoul(format_name, &endp, 10);
 
8241
 
 
8242
  /* Check for valid parse. */
 
8243
  if (*endp == '\0' && *format_name != '\0') {
 
8244
 
 
8245
    if (format_id <= DICT_TF_FORMAT_MAX) {
 
8246
 
 
8247
      return(format_id);
 
8248
    }
 
8249
  } else {
 
8250
 
 
8251
    for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
 
8252
         format_id++) {
 
8253
      const char* name;
 
8254
 
 
8255
      name = trx_sys_file_format_id_to_name(format_id);
 
8256
 
 
8257
      if (!innobase_strcasecmp(format_name, name)) {
 
8258
 
 
8259
        return(format_id);
 
8260
      }
 
8261
    }
 
8262
  }
 
8263
 
 
8264
  return(DICT_TF_FORMAT_MAX + 1);
8258
8265
}
8259
8266
 
8260
8267
/************************************************************//**
8261
8268
Validate the file format check value, is it one of "on" or "off",
8262
8269
as a side effect it sets the srv_check_file_format_at_startup variable.
8263
 
@return true if config value one of "on" or  "off" */
 
8270
@return true if config value one of "on" or  "off" */
8264
8271
static
8265
8272
bool
8266
8273
innobase_file_format_check_on_off(
8267
8274
/*==============================*/
8268
 
        const char*     format_check)   /*!< in: parameter value */
 
8275
  const char* format_check) /*!< in: parameter value */
8269
8276
{
8270
 
        bool            ret = true;
8271
 
 
8272
 
        if (!innobase_strcasecmp(format_check, "off")) {
8273
 
 
8274
 
                /* Set the value to disable checking. */
8275
 
                srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
8276
 
 
8277
 
        } else if (!innobase_strcasecmp(format_check, "on")) {
8278
 
 
8279
 
                /* Set the value to the lowest supported format. */
8280
 
                srv_check_file_format_at_startup = DICT_TF_FORMAT_51;
8281
 
        } else {
8282
 
                ret = FALSE;
8283
 
        }
8284
 
 
8285
 
        return(ret);
 
8277
  bool    ret = true;
 
8278
 
 
8279
  if (!innobase_strcasecmp(format_check, "off")) {
 
8280
 
 
8281
    /* Set the value to disable checking. */
 
8282
    srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
 
8283
 
 
8284
  } else if (!innobase_strcasecmp(format_check, "on")) {
 
8285
 
 
8286
    /* Set the value to the lowest supported format. */
 
8287
    srv_check_file_format_at_startup = DICT_TF_FORMAT_51;
 
8288
  } else {
 
8289
    ret = FALSE;
 
8290
  }
 
8291
 
 
8292
  return(ret);
8286
8293
}
8287
8294
 
8288
8295
/************************************************************//**
8289
8296
Validate the file format check config parameters, as a side effect it
8290
8297
sets the srv_check_file_format_at_startup variable.
8291
 
@return true if valid config value */
 
8298
@return true if valid config value */
8292
8299
static
8293
8300
bool
8294
8301
innobase_file_format_check_validate(
8295
8302
/*================================*/
8296
 
        const char*     format_check)   /*!< in: parameter value */
 
8303
  const char* format_check) /*!< in: parameter value */
8297
8304
{
8298
 
        uint            format_id;
8299
 
        bool            ret = true;
8300
 
 
8301
 
        format_id = innobase_file_format_name_lookup(format_check);
8302
 
 
8303
 
        if (format_id < DICT_TF_FORMAT_MAX + 1) {
8304
 
                srv_check_file_format_at_startup = format_id;
8305
 
        } else {
8306
 
                ret = false;
8307
 
        }
8308
 
 
8309
 
        return(ret);
 
8305
  uint    format_id;
 
8306
  bool    ret = true;
 
8307
 
 
8308
  format_id = innobase_file_format_name_lookup(format_check);
 
8309
 
 
8310
  if (format_id < DICT_TF_FORMAT_MAX + 1) {
 
8311
    srv_check_file_format_at_startup = format_id;
 
8312
  } else {
 
8313
    ret = false;
 
8314
  }
 
8315
 
 
8316
  return(ret);
8310
8317
}
8311
8318
 
8312
8319
/*************************************************************//**
8313
8320
Check if it is a valid file format. This function is registered as
8314
8321
a callback with MySQL.
8315
 
@return 0 for valid file format */
 
8322
@return 0 for valid file format */
8316
8323
static
8317
8324
int
8318
8325
innodb_file_format_name_validate(
8319
8326
/*=============================*/
8320
 
        Session*                        ,       /*!< in: thread handle */
8321
 
        drizzle_sys_var*        ,       /*!< in: pointer to system
8322
 
                                                variable */
8323
 
        void*                           save,   /*!< out: immediate result
8324
 
                                                for update function */
8325
 
        drizzle_value*          value)  /*!< in: incoming string */
 
8327
  Session*      , /*!< in: thread handle */
 
8328
  drizzle_sys_var*  , /*!< in: pointer to system
 
8329
            variable */
 
8330
  void*       save, /*!< out: immediate result
 
8331
            for update function */
 
8332
  drizzle_value*    value)  /*!< in: incoming string */
8326
8333
{
8327
 
        const char*     file_format_input;
8328
 
        char            buff[STRING_BUFFER_USUAL_SIZE];
8329
 
        int             len = sizeof(buff);
8330
 
 
8331
 
        ut_a(save != NULL);
8332
 
        ut_a(value != NULL);
8333
 
 
8334
 
        file_format_input = value->val_str(value, buff, &len);
8335
 
 
8336
 
        if (file_format_input != NULL) {
8337
 
                uint    format_id;
8338
 
 
8339
 
                format_id = innobase_file_format_name_lookup(
8340
 
                        file_format_input);
8341
 
 
8342
 
                if (format_id <= DICT_TF_FORMAT_MAX) {
8343
 
 
8344
 
                        *static_cast<const char**>(save) = file_format_input;
8345
 
                        return(0);
8346
 
                }
8347
 
        }
8348
 
 
8349
 
        *static_cast<const char**>(save) = NULL;
8350
 
        return(1);
 
8334
  const char* file_format_input;
 
8335
  char    buff[STRING_BUFFER_USUAL_SIZE];
 
8336
  int   len = sizeof(buff);
 
8337
 
 
8338
  ut_a(save != NULL);
 
8339
  ut_a(value != NULL);
 
8340
 
 
8341
  file_format_input = value->val_str(value, buff, &len);
 
8342
 
 
8343
  if (file_format_input != NULL) {
 
8344
    uint  format_id;
 
8345
 
 
8346
    format_id = innobase_file_format_name_lookup(
 
8347
      file_format_input);
 
8348
 
 
8349
    if (format_id <= DICT_TF_FORMAT_MAX) {
 
8350
 
 
8351
      *static_cast<const char**>(save) = file_format_input;
 
8352
      return(0);
 
8353
    }
 
8354
  }
 
8355
 
 
8356
  *static_cast<const char**>(save) = NULL;
 
8357
  return(1);
8351
8358
}
8352
8359
 
8353
8360
/****************************************************************//**
8357
8364
void
8358
8365
innodb_file_format_name_update(
8359
8366
/*===========================*/
8360
 
        Session*                        ,               /*!< in: thread handle */
8361
 
        drizzle_sys_var*        ,               /*!< in: pointer to
8362
 
                                                        system variable */
8363
 
        void*                           var_ptr,        /*!< out: where the
8364
 
                                                        formal string goes */
8365
 
        const void*                     save)           /*!< in: immediate result
8366
 
                                                        from check function */
 
8367
  Session*      ,   /*!< in: thread handle */
 
8368
  drizzle_sys_var*  ,   /*!< in: pointer to
 
8369
              system variable */
 
8370
  void*       var_ptr,  /*!< out: where the
 
8371
              formal string goes */
 
8372
  const void*     save)   /*!< in: immediate result
 
8373
              from check function */
8367
8374
{
8368
 
        const char* format_name;
8369
 
 
8370
 
        ut_a(var_ptr != NULL);
8371
 
        ut_a(save != NULL);
8372
 
 
8373
 
        format_name = *static_cast<const char*const*>(save);
8374
 
 
8375
 
        if (format_name) {
8376
 
                uint    format_id;
8377
 
 
8378
 
                format_id = innobase_file_format_name_lookup(format_name);
8379
 
 
8380
 
                if (format_id <= DICT_TF_FORMAT_MAX) {
8381
 
                        srv_file_format = format_id;
8382
 
                }
8383
 
        }
8384
 
 
8385
 
        *static_cast<const char**>(var_ptr)
8386
 
                = trx_sys_file_format_id_to_name(srv_file_format);
 
8375
  const char* format_name;
 
8376
 
 
8377
  ut_a(var_ptr != NULL);
 
8378
  ut_a(save != NULL);
 
8379
 
 
8380
  format_name = *static_cast<const char*const*>(save);
 
8381
 
 
8382
  if (format_name) {
 
8383
    uint  format_id;
 
8384
 
 
8385
    format_id = innobase_file_format_name_lookup(format_name);
 
8386
 
 
8387
    if (format_id <= DICT_TF_FORMAT_MAX) {
 
8388
      srv_file_format = format_id;
 
8389
    }
 
8390
  }
 
8391
 
 
8392
  *static_cast<const char**>(var_ptr)
 
8393
    = trx_sys_file_format_id_to_name(srv_file_format);
8387
8394
}
8388
8395
 
8389
8396
/*************************************************************//**
8390
8397
Check if valid argument to innodb_file_format_check. This
8391
8398
function is registered as a callback with MySQL.
8392
 
@return 0 for valid file format */
 
8399
@return 0 for valid file format */
8393
8400
static
8394
8401
int
8395
8402
innodb_file_format_check_validate(
8396
8403
/*==============================*/
8397
 
        Session*                        ,       /*!< in: thread handle */
8398
 
        drizzle_sys_var*        ,       /*!< in: pointer to system
8399
 
                                                variable */
8400
 
        void*                           save,   /*!< out: immediate result
8401
 
                                                for update function */
8402
 
        drizzle_value*          value)  /*!< in: incoming string */
 
8404
  Session*      , /*!< in: thread handle */
 
8405
  drizzle_sys_var*  , /*!< in: pointer to system
 
8406
            variable */
 
8407
  void*       save, /*!< out: immediate result
 
8408
            for update function */
 
8409
  drizzle_value*    value)  /*!< in: incoming string */
8403
8410
{
8404
 
        const char*     file_format_input;
8405
 
        char            buff[STRING_BUFFER_USUAL_SIZE];
8406
 
        int             len = sizeof(buff);
8407
 
 
8408
 
        ut_a(save != NULL);
8409
 
        ut_a(value != NULL);
8410
 
 
8411
 
        file_format_input = value->val_str(value, buff, &len);
8412
 
 
8413
 
        if (file_format_input != NULL) {
8414
 
 
8415
 
                /* Check if user set on/off, we want to print a suitable
8416
 
                message if they did so. */
8417
 
 
8418
 
                if (innobase_file_format_check_on_off(file_format_input)) {
8419
 
                        errmsg_printf(ERRMSG_LVL_WARN, 
8420
 
                                "InnoDB: invalid innodb_file_format_check "
8421
 
                                "value; on/off can only be set at startup or "
8422
 
                                "in the configuration file");
8423
 
                } else if (innobase_file_format_check_validate(
8424
 
                                file_format_input)) {
8425
 
 
8426
 
                        *static_cast<const char**>(save) = file_format_input;
8427
 
 
8428
 
                        return(0);
8429
 
 
8430
 
                } else {
8431
 
                        errmsg_printf(ERRMSG_LVL_WARN, 
8432
 
                                "InnoDB: invalid innodb_file_format_check "
8433
 
                                "value; can be any format up to %s "
8434
 
                                "or its equivalent numeric id",
8435
 
                                trx_sys_file_format_id_to_name(
8436
 
                                        DICT_TF_FORMAT_MAX));
8437
 
                }
8438
 
        }
8439
 
 
8440
 
        *static_cast<const char**>(save) = NULL;
8441
 
        return(1);
 
8411
  const char* file_format_input;
 
8412
  char    buff[STRING_BUFFER_USUAL_SIZE];
 
8413
  int   len = sizeof(buff);
 
8414
 
 
8415
  ut_a(save != NULL);
 
8416
  ut_a(value != NULL);
 
8417
 
 
8418
  file_format_input = value->val_str(value, buff, &len);
 
8419
 
 
8420
  if (file_format_input != NULL) {
 
8421
 
 
8422
    /* Check if user set on/off, we want to print a suitable
 
8423
    message if they did so. */
 
8424
 
 
8425
    if (innobase_file_format_check_on_off(file_format_input)) {
 
8426
      errmsg_printf(ERRMSG_LVL_WARN, 
 
8427
        "InnoDB: invalid innodb_file_format_check "
 
8428
        "value; on/off can only be set at startup or "
 
8429
        "in the configuration file");
 
8430
    } else if (innobase_file_format_check_validate(
 
8431
        file_format_input)) {
 
8432
 
 
8433
      *static_cast<const char**>(save) = file_format_input;
 
8434
 
 
8435
      return(0);
 
8436
 
 
8437
    } else {
 
8438
      errmsg_printf(ERRMSG_LVL_WARN, 
 
8439
        "InnoDB: invalid innodb_file_format_check "
 
8440
        "value; can be any format up to %s "
 
8441
        "or its equivalent numeric id",
 
8442
        trx_sys_file_format_id_to_name(
 
8443
          DICT_TF_FORMAT_MAX));
 
8444
    }
 
8445
  }
 
8446
 
 
8447
  *static_cast<const char**>(save) = NULL;
 
8448
  return(1);
8442
8449
}
8443
8450
 
8444
8451
/****************************************************************//**
8448
8455
void
8449
8456
innodb_file_format_check_update(
8450
8457
/*============================*/
8451
 
        Session*                        session,        /*!< in: thread handle */
8452
 
        drizzle_sys_var*        ,               /*!< in: pointer to
8453
 
                                                        system variable */
8454
 
        void*                           var_ptr,        /*!< out: where the
8455
 
                                                        formal string goes */
8456
 
        const void*                     save)           /*!< in: immediate result
8457
 
                                                        from check function */
 
8458
  Session*      session,  /*!< in: thread handle */
 
8459
  drizzle_sys_var*  ,   /*!< in: pointer to
 
8460
              system variable */
 
8461
  void*       var_ptr,  /*!< out: where the
 
8462
              formal string goes */
 
8463
  const void*     save)   /*!< in: immediate result
 
8464
              from check function */
8458
8465
{
8459
 
        const char*     format_name_in;
8460
 
        const char**    format_name_out;
8461
 
        uint            format_id;
8462
 
 
8463
 
        ut_a(save != NULL);
8464
 
        ut_a(var_ptr != NULL);
8465
 
 
8466
 
        format_name_in = *static_cast<const char*const*>(save);
8467
 
 
8468
 
        if (!format_name_in) {
8469
 
 
8470
 
                return;
8471
 
        }
8472
 
 
8473
 
        format_id = innobase_file_format_name_lookup(format_name_in);
8474
 
 
8475
 
        if (format_id > DICT_TF_FORMAT_MAX) {
8476
 
                /* DEFAULT is "on", which is invalid at runtime. */
8477
 
                push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
8478
 
                                    ER_WRONG_ARGUMENTS,
8479
 
                                    "Ignoring SET innodb_file_format=%s",
8480
 
                                    format_name_in);
8481
 
                return;
8482
 
        }
8483
 
 
8484
 
        format_name_out = static_cast<const char**>(var_ptr);
8485
 
 
8486
 
        /* Update the max format id in the system tablespace. */
8487
 
        if (trx_sys_file_format_max_set(format_id, format_name_out)) {
8488
 
                ut_print_timestamp(stderr);
8489
 
                fprintf(stderr,
8490
 
                        " [Info] InnoDB: the file format in the system "
8491
 
                        "tablespace is now set to %s.\n", *format_name_out);
8492
 
        }
 
8466
  const char* format_name_in;
 
8467
  const char**  format_name_out;
 
8468
  uint    format_id;
 
8469
 
 
8470
  ut_a(save != NULL);
 
8471
  ut_a(var_ptr != NULL);
 
8472
 
 
8473
  format_name_in = *static_cast<const char*const*>(save);
 
8474
 
 
8475
  if (!format_name_in) {
 
8476
 
 
8477
    return;
 
8478
  }
 
8479
 
 
8480
  format_id = innobase_file_format_name_lookup(format_name_in);
 
8481
 
 
8482
  if (format_id > DICT_TF_FORMAT_MAX) {
 
8483
    /* DEFAULT is "on", which is invalid at runtime. */
 
8484
    push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
8485
            ER_WRONG_ARGUMENTS,
 
8486
            "Ignoring SET innodb_file_format=%s",
 
8487
            format_name_in);
 
8488
    return;
 
8489
  }
 
8490
 
 
8491
  format_name_out = static_cast<const char**>(var_ptr);
 
8492
 
 
8493
  /* Update the max format id in the system tablespace. */
 
8494
  if (trx_sys_file_format_max_set(format_id, format_name_out)) {
 
8495
    ut_print_timestamp(stderr);
 
8496
    fprintf(stderr,
 
8497
      " [Info] InnoDB: the file format in the system "
 
8498
      "tablespace is now set to %s.\n", *format_name_out);
 
8499
  }
8493
8500
}
8494
8501
 
8495
8502
/****************************************************************//**
8499
8506
void
8500
8507
innodb_adaptive_hash_index_update(
8501
8508
/*==============================*/
8502
 
        Session*                        ,               /*!< in: thread handle */
8503
 
        drizzle_sys_var*        ,               /*!< in: pointer to
8504
 
                                                        system variable */
8505
 
        void*                           ,       /*!< out: where the
8506
 
                                                        formal string goes */
8507
 
        const void*                     save)           /*!< in: immediate result
8508
 
                                                        from check function */
 
8509
  Session*      ,   /*!< in: thread handle */
 
8510
  drizzle_sys_var*  ,   /*!< in: pointer to
 
8511
              system variable */
 
8512
  void*       , /*!< out: where the
 
8513
              formal string goes */
 
8514
  const void*     save)   /*!< in: immediate result
 
8515
              from check function */
8509
8516
{
8510
 
        if (*(bool*) save) {
8511
 
                btr_search_enable();
8512
 
        } else {
8513
 
                btr_search_disable();
8514
 
        }
 
8517
  if (*(bool*) save) {
 
8518
    btr_search_enable();
 
8519
  } else {
 
8520
    btr_search_disable();
 
8521
  }
8515
8522
}
8516
8523
 
8517
8524
/*************************************************************//**
8518
8525
Check if it is a valid value of innodb_change_buffering.  This function is
8519
8526
registered as a callback with MySQL.
8520
 
@return 0 for valid innodb_change_buffering */
 
8527
@return 0 for valid innodb_change_buffering */
8521
8528
static
8522
8529
int
8523
8530
innodb_change_buffering_validate(
8524
8531
/*=============================*/
8525
 
        Session*                        ,       /*!< in: thread handle */
8526
 
        drizzle_sys_var*        ,       /*!< in: pointer to system
8527
 
                                                variable */
8528
 
        void*                           save,   /*!< out: immediate result
8529
 
                                                for update function */
8530
 
        drizzle_value*          value)  /*!< in: incoming string */
 
8532
  Session*      , /*!< in: thread handle */
 
8533
  drizzle_sys_var*  , /*!< in: pointer to system
 
8534
            variable */
 
8535
  void*       save, /*!< out: immediate result
 
8536
            for update function */
 
8537
  drizzle_value*    value)  /*!< in: incoming string */
8531
8538
{
8532
 
        const char*     change_buffering_input;
8533
 
        char            buff[STRING_BUFFER_USUAL_SIZE];
8534
 
        int             len = sizeof(buff);
8535
 
 
8536
 
        ut_a(save != NULL);
8537
 
        ut_a(value != NULL);
8538
 
 
8539
 
        change_buffering_input = value->val_str(value, buff, &len);
8540
 
 
8541
 
        if (change_buffering_input != NULL) {
8542
 
                ulint   use;
8543
 
 
8544
 
                for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
8545
 
                     use++) {
8546
 
                        if (!innobase_strcasecmp(
8547
 
                                    change_buffering_input,
8548
 
                                    innobase_change_buffering_values[use])) {
8549
 
                                *(ibuf_use_t*) save = (ibuf_use_t) use;
8550
 
                                return(0);
8551
 
                        }
8552
 
                }
8553
 
        }
8554
 
 
8555
 
        return(1);
 
8539
  const char* change_buffering_input;
 
8540
  char    buff[STRING_BUFFER_USUAL_SIZE];
 
8541
  int   len = sizeof(buff);
 
8542
 
 
8543
  ut_a(save != NULL);
 
8544
  ut_a(value != NULL);
 
8545
 
 
8546
  change_buffering_input = value->val_str(value, buff, &len);
 
8547
 
 
8548
  if (change_buffering_input != NULL) {
 
8549
    ulint use;
 
8550
 
 
8551
    for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
 
8552
         use++) {
 
8553
      if (!innobase_strcasecmp(
 
8554
            change_buffering_input,
 
8555
            innobase_change_buffering_values[use])) {
 
8556
        *(ibuf_use_t*) save = (ibuf_use_t) use;
 
8557
        return(0);
 
8558
      }
 
8559
    }
 
8560
  }
 
8561
 
 
8562
  return(1);
8556
8563
}
8557
8564
 
8558
8565
/****************************************************************//**
8562
8569
void
8563
8570
innodb_change_buffering_update(
8564
8571
/*===========================*/
8565
 
        Session*                        ,               /*!< in: thread handle */
8566
 
        drizzle_sys_var*        ,               /*!< in: pointer to
8567
 
                                                        system variable */
8568
 
        void*                           var_ptr,        /*!< out: where the
8569
 
                                                        formal string goes */
8570
 
        const void*                     save)           /*!< in: immediate result
8571
 
                                                        from check function */
 
8572
  Session*      ,   /*!< in: thread handle */
 
8573
  drizzle_sys_var*  ,   /*!< in: pointer to
 
8574
              system variable */
 
8575
  void*       var_ptr,  /*!< out: where the
 
8576
              formal string goes */
 
8577
  const void*     save)   /*!< in: immediate result
 
8578
              from check function */
8572
8579
{
8573
 
        ut_a(var_ptr != NULL);
8574
 
        ut_a(save != NULL);
8575
 
        ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT);
8576
 
 
8577
 
        ibuf_use = *(const ibuf_use_t*) save;
8578
 
 
8579
 
        *(const char**) var_ptr = innobase_change_buffering_values[ibuf_use];
 
8580
  ut_a(var_ptr != NULL);
 
8581
  ut_a(save != NULL);
 
8582
  ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT);
 
8583
 
 
8584
  ibuf_use = *(const ibuf_use_t*) save;
 
8585
 
 
8586
  *(const char**) var_ptr = innobase_change_buffering_values[ibuf_use];
8580
8587
}
8581
8588
 
8582
8589
/* plugin options */
8803
8810
  "1 => New style AUTOINC locking                            "
8804
8811
  "2 => No AUTOINC locking (unsafe for SBR)",
8805
8812
  NULL, NULL,
8806
 
  AUTOINC_NO_LOCKING,   /* Default setting */
8807
 
  AUTOINC_OLD_STYLE_LOCKING,    /* Minimum value */
8808
 
  AUTOINC_NO_LOCKING, 0);       /* Maximum value */
 
8813
  AUTOINC_NO_LOCKING, /* Default setting */
 
8814
  AUTOINC_OLD_STYLE_LOCKING,  /* Minimum value */
 
8815
  AUTOINC_NO_LOCKING, 0); /* Maximum value */
8809
8816
 
8810
8817
static DRIZZLE_SYSVAR_STR(version, innodb_version_str,
8811
8818
  PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
8900
8907
DRIZZLE_DECLARE_PLUGIN_END;
8901
8908
 
8902
8909
int ha_innobase::read_range_first(const key_range *start_key,
8903
 
                                  const key_range *end_key,
8904
 
                                  bool eq_range_arg,
8905
 
                                  bool sorted)
 
8910
          const key_range *end_key,
 
8911
          bool eq_range_arg,
 
8912
          bool sorted)
8906
8913
{
8907
8914
  int res;
8908
8915
  //if (!eq_range_arg)
8936
8943
innobase_commit_concurrency_init_default(void)
8937
8944
/*==========================================*/
8938
8945
{
8939
 
        DRIZZLE_SYSVAR_NAME(commit_concurrency).def_val
8940
 
                = innobase_commit_concurrency;
 
8946
  DRIZZLE_SYSVAR_NAME(commit_concurrency).def_val
 
8947
    = innobase_commit_concurrency;
8941
8948
}
8942
8949
 
8943
8950
#ifdef UNIV_COMPILE_TEST_FUNCS
8944
8951
 
8945
8952
typedef struct innobase_convert_name_test_struct {
8946
 
        char*           buf;
8947
 
        ulint           buflen;
8948
 
        const char*     id;
8949
 
        ulint           idlen;
8950
 
        void*           session;
8951
 
        ibool           file_id;
 
8953
  char*   buf;
 
8954
  ulint   buflen;
 
8955
  const char* id;
 
8956
  ulint   idlen;
 
8957
  void*   session;
 
8958
  ibool   file_id;
8952
8959
 
8953
 
        const char*     expected;
 
8960
  const char* expected;
8954
8961
} innobase_convert_name_test_t;
8955
8962
 
8956
8963
void
8957
8964
test_innobase_convert_name()
8958
8965
{
8959
 
        char    buf[1024];
8960
 
        ulint   i;
8961
 
 
8962
 
        innobase_convert_name_test_t test_input[] = {
8963
 
                {buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
8964
 
                {buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
8965
 
                {buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
8966
 
                {buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
8967
 
                {buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
8968
 
 
8969
 
                {buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
8970
 
                {buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
8971
 
                {buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
8972
 
                {buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
8973
 
                {buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
8974
 
                {buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
8975
 
                {buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
8976
 
 
8977
 
                {buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
8978
 
                        "\"#mysql50#ab\"\"cd\""},
8979
 
                {buf, 17, "ab\"cd", 5, NULL, TRUE,
8980
 
                        "\"#mysql50#ab\"\"cd\""},
8981
 
                {buf, 16, "ab\"cd", 5, NULL, TRUE,
8982
 
                        "\"#mysql50#ab\"\"c\""},
8983
 
                {buf, 15, "ab\"cd", 5, NULL, TRUE,
8984
 
                        "\"#mysql50#ab\"\"\""},
8985
 
                {buf, 14, "ab\"cd", 5, NULL, TRUE,
8986
 
                        "\"#mysql50#ab\""},
8987
 
                {buf, 13, "ab\"cd", 5, NULL, TRUE,
8988
 
                        "\"#mysql50#ab\""},
8989
 
                {buf, 12, "ab\"cd", 5, NULL, TRUE,
8990
 
                        "\"#mysql50#a\""},
8991
 
                {buf, 11, "ab\"cd", 5, NULL, TRUE,
8992
 
                        "\"#mysql50#\""},
8993
 
                {buf, 10, "ab\"cd", 5, NULL, TRUE,
8994
 
                        "\"#mysql50\""},
8995
 
 
8996
 
                {buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
8997
 
                {buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
8998
 
                {buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
8999
 
                {buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
9000
 
                {buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9001
 
                {buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
9002
 
                {buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
9003
 
                {buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
9004
 
                {buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
9005
 
                /* XXX probably "" is a better result in this case
9006
 
                {buf, 1, "ab/cd", 5, NULL, TRUE, "."},
9007
 
                */
9008
 
                {buf, 0, "ab/cd", 5, NULL, TRUE, ""},
9009
 
        };
9010
 
 
9011
 
        for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
9012
 
 
9013
 
                char*   end;
9014
 
                ibool   ok = TRUE;
9015
 
                size_t  res_len;
9016
 
 
9017
 
                fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
9018
 
                        test_input[i].buflen,
9019
 
                        test_input[i].id,
9020
 
                        test_input[i].idlen,
9021
 
                        test_input[i].expected);
9022
 
 
9023
 
                end = innobase_convert_name(
9024
 
                        test_input[i].buf,
9025
 
                        test_input[i].buflen,
9026
 
                        test_input[i].id,
9027
 
                        test_input[i].idlen,
9028
 
                        test_input[i].session,
9029
 
                        test_input[i].file_id);
9030
 
 
9031
 
                res_len = (size_t) (end - test_input[i].buf);
9032
 
 
9033
 
                if (res_len != strlen(test_input[i].expected)) {
9034
 
 
9035
 
                        fprintf(stderr, "unexpected len of the result: %u, "
9036
 
                                "expected: %u\n", (unsigned) res_len,
9037
 
                                (unsigned) strlen(test_input[i].expected));
9038
 
                        ok = FALSE;
9039
 
                }
9040
 
 
9041
 
                if (memcmp(test_input[i].buf,
9042
 
                           test_input[i].expected,
9043
 
                           strlen(test_input[i].expected)) != 0
9044
 
                    || !ok) {
9045
 
 
9046
 
                        fprintf(stderr, "unexpected result: %.*s, "
9047
 
                                "expected: %s\n", (int) res_len,
9048
 
                                test_input[i].buf,
9049
 
                                test_input[i].expected);
9050
 
                        ok = FALSE;
9051
 
                }
9052
 
 
9053
 
                if (ok) {
9054
 
                        fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
9055
 
                                buf);
9056
 
                } else {
9057
 
                        fprintf(stderr, "FAILED\n\n");
9058
 
                        return;
9059
 
                }
9060
 
        }
 
8966
  char  buf[1024];
 
8967
  ulint i;
 
8968
 
 
8969
  innobase_convert_name_test_t test_input[] = {
 
8970
    {buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
 
8971
    {buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
 
8972
    {buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
 
8973
    {buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
 
8974
    {buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
 
8975
 
 
8976
    {buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
8977
    {buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
8978
    {buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
8979
    {buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
8980
    {buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
 
8981
    {buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
 
8982
    {buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
 
8983
 
 
8984
    {buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
 
8985
      "\"#mysql50#ab\"\"cd\""},
 
8986
    {buf, 17, "ab\"cd", 5, NULL, TRUE,
 
8987
      "\"#mysql50#ab\"\"cd\""},
 
8988
    {buf, 16, "ab\"cd", 5, NULL, TRUE,
 
8989
      "\"#mysql50#ab\"\"c\""},
 
8990
    {buf, 15, "ab\"cd", 5, NULL, TRUE,
 
8991
      "\"#mysql50#ab\"\"\""},
 
8992
    {buf, 14, "ab\"cd", 5, NULL, TRUE,
 
8993
      "\"#mysql50#ab\""},
 
8994
    {buf, 13, "ab\"cd", 5, NULL, TRUE,
 
8995
      "\"#mysql50#ab\""},
 
8996
    {buf, 12, "ab\"cd", 5, NULL, TRUE,
 
8997
      "\"#mysql50#a\""},
 
8998
    {buf, 11, "ab\"cd", 5, NULL, TRUE,
 
8999
      "\"#mysql50#\""},
 
9000
    {buf, 10, "ab\"cd", 5, NULL, TRUE,
 
9001
      "\"#mysql50\""},
 
9002
 
 
9003
    {buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
 
9004
    {buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
 
9005
    {buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
 
9006
    {buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
 
9007
    {buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
 
9008
    {buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
 
9009
    {buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
 
9010
    {buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
 
9011
    {buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
 
9012
    /* XXX probably "" is a better result in this case
 
9013
    {buf, 1, "ab/cd", 5, NULL, TRUE, "."},
 
9014
    */
 
9015
    {buf, 0, "ab/cd", 5, NULL, TRUE, ""},
 
9016
  };
 
9017
 
 
9018
  for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
 
9019
 
 
9020
    char* end;
 
9021
    ibool ok = TRUE;
 
9022
    size_t  res_len;
 
9023
 
 
9024
    fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
 
9025
      test_input[i].buflen,
 
9026
      test_input[i].id,
 
9027
      test_input[i].idlen,
 
9028
      test_input[i].expected);
 
9029
 
 
9030
    end = innobase_convert_name(
 
9031
      test_input[i].buf,
 
9032
      test_input[i].buflen,
 
9033
      test_input[i].id,
 
9034
      test_input[i].idlen,
 
9035
      test_input[i].session,
 
9036
      test_input[i].file_id);
 
9037
 
 
9038
    res_len = (size_t) (end - test_input[i].buf);
 
9039
 
 
9040
    if (res_len != strlen(test_input[i].expected)) {
 
9041
 
 
9042
      fprintf(stderr, "unexpected len of the result: %u, "
 
9043
        "expected: %u\n", (unsigned) res_len,
 
9044
        (unsigned) strlen(test_input[i].expected));
 
9045
      ok = FALSE;
 
9046
    }
 
9047
 
 
9048
    if (memcmp(test_input[i].buf,
 
9049
         test_input[i].expected,
 
9050
         strlen(test_input[i].expected)) != 0
 
9051
        || !ok) {
 
9052
 
 
9053
      fprintf(stderr, "unexpected result: %.*s, "
 
9054
        "expected: %s\n", (int) res_len,
 
9055
        test_input[i].buf,
 
9056
        test_input[i].expected);
 
9057
      ok = FALSE;
 
9058
    }
 
9059
 
 
9060
    if (ok) {
 
9061
      fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
 
9062
        buf);
 
9063
    } else {
 
9064
      fprintf(stderr, "FAILED\n\n");
 
9065
      return;
 
9066
    }
 
9067
  }
9061
9068
}
9062
9069
 
9063
9070
#endif /* UNIV_COMPILE_TEST_FUNCS */