MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbInterpretedCode.hpp
1 /*
2  Copyright (C) 2007, 2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc.
3  All rights reserved. Use is subject to license terms.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #ifndef NdbInterpretedCode_H
20 #define NdbInterpretedCode_H
21 
22 #include <ndb_types.h>
23 #include "ndbapi_limits.h"
24 
25 #include "NdbDictionary.hpp"
26 #include "NdbError.hpp"
27 
28 class NdbTableImpl;
29 class NdbColumnImpl;
30 
31 /*
32  @brief Stand-alone interpreted programs, for use with NdbRecord
33 
34  @details This class is used to prepare an NDB interpreted program for use
35  in operations created using NdbRecord, or scans created using the old
36  API. The ScanFilter class can also be used to generate an NDB interpreted
37  program using NdbInterpretedCode.
38 
39  Usage :
40  1) Create NdbInterpretedCode object, optionally supplying a table
41  for the program to operate on, and a buffer for program storage
42  and finalisation
43  Note :
44  - If no table is supplied, then only instructions which do not
45  access table attributes can be used.
46  - If no buffer is supplied, then an internal buffer will be
47  dynamically allocated and extended as necessary.
48  2) Add instructions and labels to the NdbInterpretedCode object
49  by calling the methods below.
50  3) When the program is complete, finalise it by calling the
51  finalise() method. This will resolve internal branches and
52  calls to label and subroutine offsets.
53  4) Use the program with NdbRecord operations and scans by passing
54  it at operation definition time via the OperationOptions or
55  ScanOptions parameters.
56  Alternatively, use the program with old-Api scans by passing it
57  via the setInterpretedProgram() method.
58  5) When the program is no longer required, the NdbInterpretedCode
59  object can be deleted, along with any user-supplied buffer.
60 
61  Notes :
62  a) Each NDBAPI operation applies to one table, and so does any
63  NdbInterpretedCode program attached to that operation.
64  b) A single finalised NdbInterpretedCode program can be used by
65  more than one operation. It need not be 'rebuilt' for each
66  operation.
67  c) Methods have minimal error checks, for efficiency
68  d) Note that this interface may be subject to change without notice.
69  The NdbScanFilter API is a more stable Api for defining scan-filter
70  style programs.
71 */
73 {
74 public:
93  Uint32 *buffer= 0,
94  Uint32 buffer_word_size= 0);
95 
97 
98  /* Register constant loads
99  * -----------------------
100  * These instructions allow numeric constants (and null)
101  * to be loaded into the interpreter's registers
102  *
103  * Space required Buffer Request message
104  * load_const_null 1 word 1 word
105  * load_const_u16 1 word 1 word
106  * load_const_u32 2 words 2 words
107  * load_const_u64 3 words 3 words
108  *
109  * @param RegDest Register to load constant into
110  * @param Constant Value to load
111  * @return 0 if successful, -1 otherwise
112  */
113  int load_const_null(Uint32 RegDest);
114  int load_const_u16(Uint32 RegDest, Uint32 Constant);
115  int load_const_u32(Uint32 RegDest, Uint32 Constant);
116  int load_const_u64(Uint32 RegDest, Uint64 Constant);
117 
118  /* Register to / from table attribute load and store
119  * -------------------------------------------------
120  * These instructions allow data to be moved between the
121  * interpreter's numeric registers and numeric columns
122  * in the current row.
123  * These instructions require that the table being operated
124  * on was specified with the NdbInterpretedCode object
125  * was constructed.
126  *
127  * Space required Buffer Request message
128  * read_attr 1 word 1 word
129  * write_attr 1 word 1 word
130  *
131  * @param RegDest Register to load data into
132  * @param attrId Table attribute to use
133  * @param column Table column to use
134  * @param RegSource Register to store data from
135  * @return 0 if successful, -1 otherwise
136  */
137  int read_attr(Uint32 RegDest, Uint32 attrId);
138  int read_attr(Uint32 RegDest, const NdbDictionary::Column *column);
139  int write_attr(Uint32 attrId, Uint32 RegSource);
140  int write_attr(const NdbDictionary::Column *column, Uint32 RegSource);
141 
142  /* Register arithmetic
143  * -------------------
144  * These instructions provide arithmetic operations on the
145  * interpreter's registers.
146  *
147  * *RegDest= *RegSouce1 <operator> *RegSource2
148  *
149  * Space required Buffer Request message
150  * add_reg 1 word 1 word
151  * sub_reg 1 word 1 word
152  *
153  * @param RegDest Register to store operation result in
154  * @param RegSource1 Register to use as LHS of operator
155  * @param RegSource2 Register to use as RHS of operator
156  * @return 0 if successful, -1 otherwise
157  */
158  int add_reg(Uint32 RegDest, Uint32 RegSource1, Uint32 RegSource2);
159  int sub_reg(Uint32 RegDest, Uint32 RegSource1, Uint32 RegSource2);
160 
161  /* Control flow
162  * ------------
163  */
164 
165  /* Label definition
166  * ----------------
167  * Space required Buffer Request message
168  * def_label 2 words 0 words
169  *
170  * @param LabelNum Unique number within this program for the label
171  * @return 0 if successful, -1 otherwise
172  */
173  int def_label(int LabelNum);
174 
175  /* Unconditional jump
176  * ------------------
177  * Space required Buffer Request message
178  * branch_label 1 word 1 word
179  *
180  * @param Label : Program label to jump to
181  * @return 0 if successful, -1 otherwise
182  */
183  int branch_label(Uint32 Label);
184 
185  /* Register based conditional branch ops
186  * -------------------------------------
187  * These instructions are used to branch based on numeric
188  * register to register comparisons.
189  *
190  * if (RegLvalue <cond> RegRvalue)
191  * goto Label;
192  *
193  * Space required Buffer Request message
194  * branch_* 1 word 1 word
195  *
196  * @param RegLValue register to use as left hand side of condition
197  * @param RegRValue register to use as right hand side of condition
198  * @param Label Program label to jump to if condition is true
199  * @return 0 if successfull, -1 otherwise.
200  */
201  int branch_ge(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label);
202  int branch_gt(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label);
203  int branch_le(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label);
204  int branch_lt(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label);
205  int branch_eq(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label);
206  int branch_ne(Uint32 RegLvalue, Uint32 RegRvalue, Uint32 Label);
207  int branch_ne_null(Uint32 RegLvalue, Uint32 Label);
208  int branch_eq_null(Uint32 RegLvalue, Uint32 Label);
209 
210 
211  /* Table data based conditional branch ops
212  * ---------------------------------------
213  * These instructions are used to branch based on comparisons
214  * between columns and constants.
215  *
216  * These instructions require that the table being operated
217  * upon was supplied when the NdbInterpretedCode object was
218  * constructed.
219  *
220  * The comparison constant pointed to by val should
221  * be in normal column format as described in the
222  * documentation for NdbOperation.equal()
223  * NOTE THE ORDER OF THE COMPARISON AND ARGUMENTS
224  *
225  * if ( *val <cond> ValueOf(AttrId) )
226  * goto Label;
227  *
228  * Space required Buffer Request message
229  * branch_col_*_null 2 words 2 words
230  * branch_col_* 2 words + 2 words +
231  * type length type length
232  * rounded to rounded to
233  * nearest word nearest word
234  *
235  * Only significant words stored/
236  * sent for VAR* types
237  *
238  * @param val ptr to const value to compare against
239  * @param unused unnecessary
240  * @param attrId column to compare
241  * @param Label Program label to jump to if condition is true
242  * @return 0 if successful, -1 otherwise.
243  */
244  int branch_col_eq(const void * val, Uint32 unused, Uint32 attrId,
245  Uint32 Label);
246  int branch_col_ne(const void * val, Uint32 unused, Uint32 attrId,
247  Uint32 Label);
248  int branch_col_lt(const void * val, Uint32 unused, Uint32 attrId,
249  Uint32 Label);
250  int branch_col_le(const void * val, Uint32 unused, Uint32 attrId,
251  Uint32 Label);
252  int branch_col_gt(const void * val, Uint32 unused, Uint32 attrId,
253  Uint32 Label);
254  int branch_col_ge(const void * val, Uint32 unused, Uint32 attrId,
255  Uint32 Label);
256  int branch_col_eq_null(Uint32 attrId, Uint32 Label);
257  int branch_col_ne_null(Uint32 attrId, Uint32 Label);
258 
259 
260  /* Table based pattern match conditional operations
261  * ------------------------------------------------
262  * These instructions are used to branch based on comparisons
263  * between CHAR/BINARY/VARCHAR/VARBINARY columns and
264  * reg-exp patterns.
265  *
266  * These instructions require that the table being operated
267  * upon was supplied when the NdbInterpretedCode object was
268  * constructed.
269  *
270  * The pattern passed in val should be in plain CHAR
271  * format even if the column is a VARCHAR
272  * (i.e. no leading length bytes)
273  *
274  * if (ValueOf(attrId) <LIKE/NOTLIKE> *val)
275  * goto Label;
276  *
277  * Space required Buffer Request message
278  * branch_col_like/
279  * branch_col_notlike 2 words + 2 words +
280  * len bytes len bytes
281  * rounded to rounded to
282  * nearest word nearest word
283  *
284  * @param val ptr to const pattern to match against
285  * @param len length in bytes of const pattern
286  * @param attrId column to compare
287  * @param Label Program label to jump to if condition is true
288  * @return 0 if successful, -1 otherwise.
289  *
290  */
291  int branch_col_like(const void * val, Uint32 len, Uint32 attrId,
292  Uint32 Label);
293  int branch_col_notlike(const void * val, Uint32 len, Uint32 attrId,
294  Uint32 Label);
295 
296  /* Table based bitwise logical conditional operations
297  * --------------------------------------------------
298  * These instructions are used to branch based on the
299  * result of logical AND between Bit type column data
300  * and a bitmask pattern.
301  *
302  * These instructions require that the table being operated
303  * upon was supplied when the NdbInterpretedCode object was
304  * constructed.
305  *
306  * The mask value should be the same size as the bit column
307  * being compared.
308  * Bitfields are passed in/out of NdbApi as 32-bit words
309  * with bits set from lsb to msb.
310  * The platform's endianness controls which byte contains
311  * the ls bits.
312  * x86= first(0th) byte. Sparc/PPC= last(3rd byte)
313  *
314  * To set bit n of a bitmask to 1 from a Uint32* mask :
315  * mask[n >> 5] |= (1 << (n & 31))
316  *
317  * if (BitWiseAnd(ValueOf(attrId), *mask) <EQ/NE> <*mask/0>)
318  * goto Label;
319  *
320  * Space required Buffer Request message
321  * branch_col_and_mask_eq_mask/
322  * branch_col_and_mask_ne_mask/
323  * branch_col_and_mask_eq_zero/
324  * branch_col_and_mask_ne_zero
325  * 2 words + 2 words +
326  * column width column width
327  * rounded to rounded to
328  * nearest word nearest word
329  *
330  * @param mask ptr to const mask to use
331  * @param unused unnecessary
332  * @param attrId column to compare
333  * @param Label Program label to jump to if condition is true
334  * @return 0 if successful, -1 otherwise.
335  *
336  */
337  int branch_col_and_mask_eq_mask(const void * mask, Uint32 unused, Uint32 attrId, Uint32 Label);
338  int branch_col_and_mask_ne_mask(const void * mask, Uint32 unused, Uint32 attrId, Uint32 Label);
339  int branch_col_and_mask_eq_zero(const void * mask, Uint32 unused, Uint32 attrId, Uint32 Label);
340  int branch_col_and_mask_ne_zero(const void * mask, Uint32 unused, Uint32 attrId, Uint32 Label);
341 
342 
343  /* Program results
344  * ---------------
345  * These instructions indicate to the interpreter that processing
346  * for the current row is finished.
347  * In a scanning operation, the program may then be re-run for
348  * the next row.
349  * In a non-scanning operation, the program will not be run again.
350  *
351  */
352 
353  /* interpret_exit_ok
354  *
355  * Scanning operation : This row should be returned as part of
356  * the scan. Move onto next row.
357  * Non-scanning operation : Exit interpreted program.
358  *
359  * Space required Buffer Request message
360  * interpret_exit_ok 1 word 1 word
361  *
362  * @return 0 if successful, -1 otherwise.
363  */
364  int interpret_exit_ok();
365 
366  /* interpret_exit_nok
367  *
368  * Scanning operation : This row should not be returned as part
369  * of the scan. Move onto next row.
370  * Non-scanning operation : Abort the operation
371  *
372  * Space required Buffer Request message
373  * interpret_exit_nok 1 word 1 word
374  *
375  * @param ErrorCode An error code which will be returned as part
376  * of the operation. If not supplied, defaults to 899.
377  * @return 0 if successful, -1 otherwise
378  */
379  int interpret_exit_nok(Uint32 ErrorCode);
380  int interpret_exit_nok();
381 
382  /* interpret_exit_last_row
383  *
384  * Scanning operation : This row should be returned as part of
385  * the scan. No more rows should be scanned
386  * in this fragment.
387  * Non-scanning operation : Abort the operation
388  *
389  * Space required Buffer Request message
390  * interpret_exit_last_row 1 word 1 word
391  *
392  * @return 0 if successful, -1 otherwise
393  */
394  int interpret_exit_last_row();
395 
396  /* Utilities
397  * These utilities insert multiple instructions into the
398  * program and use specific registers to accomplish their
399  * goal.
400  */
401 
402  /* add_val
403  * Adds the supplied numeric value (32 or 64 bit) to the supplied
404  * column.
405  *
406  * Uses registers 6 and 7, destroying any contents they have.
407  * After execution : R6 = old column value R7 = new column value
408  *
409  * These utilities require that the table being operated
410  * upon was supplied when the NdbInterpretedCode object was
411  * constructed.
412  *
413  * Space required Buffer Request message
414  * add_val(32bit) 4 words + 1 word if aValue >= 2^16
415  * add_val(64 bit) 4 words + 1 word if aValue >= 2^16
416  * + 1 word if aValue >= 2^32
417  *
418  * @param attrId Column to be added to
419  * @param aValue Value to add
420  * @return 0 if successful, -1 otherwise
421  */
422  int add_val(Uint32 attrId, Uint32 aValue);
423  int add_val(Uint32 attrId, Uint64 aValue);
424 
425  /* sub_val
426  * Subtracts the supplied value (32 or 64 bit) from the
427  * value of the supplied column.
428  *
429  * Uses registers 6 and 7, destroying any contents they have.
430  * After execution : R6 = old column value R7 = new column value
431  *
432  * These utilities require that the table being operated
433  * upon was supplied when the NdbInterpretedCode object was
434  * constructed.
435  *
436  * Space required Buffer Request message
437  * sub_val(32bit) 4 words + 1 word if aValue >= 2^16
438  * sub_val(64 bit) 4 words + 1 word if aValue >= 2^16
439  * + 1 word if aValue >= 2^32
440  *
441  * @param attrId Column to be subtracted from
442  * @param aValue Value to subtrace
443  * @param 0 if successful, -1 otherwise
444  */
445  int sub_val(Uint32 attrId, Uint32 aValue);
446  int sub_val(Uint32 attrId, Uint64 aValue);
447 
448 
449  /* Subroutines
450  * Subroutines which can be called from the 'main' part of
451  * an interpreted program can be defined.
452  * Subroutines are identified with a number. Subroutine
453  * numbers must be contiguous.
454  */
455 
471  int def_sub(Uint32 SubroutineNumber);
472 
487  int call_sub(Uint32 SubroutineNumber);
488 
498  int ret_sub();
499 
511  int finalise();
512 
520  const NdbDictionary::Table* getTable() const;
521 
527  const struct NdbError & getNdbError() const;
528 
529 
535  Uint32 getWordsUsed() const;
536 
541  int copy(const NdbInterpretedCode& src);
542 
543 private:
544  friend class NdbOperation;
545  friend class NdbScanOperation;
546  friend class NdbQueryOperationImpl;
547  friend class NdbQueryOptionsImpl;
548 
549  static const Uint32 MaxReg= 8;
550  static const Uint32 MaxLabels= 65535;
551  static const Uint32 MaxSubs=65535;
552  static const Uint32 MaxDynamicBufSize= NDB_MAX_SCANFILTER_SIZE_IN_WORDS;
553 
554  const NdbTableImpl *m_table_impl;
555  Uint32 *m_buffer;
556  Uint32 m_buffer_length; // In words
557  Uint32 *m_internal_buffer; // Self-managed buffer
558  Uint32 m_number_of_labels;
559  Uint32 m_number_of_subs;
560  Uint32 m_number_of_calls;
561 
562  /* Offset of last meta info record from start of m_buffer
563  * in words
564  */
565  Uint32 m_last_meta_pos;
566 
567  /* Number of words used for instructions. Includes main program
568  * and subroutines
569  */
570  Uint32 m_instructions_length;
571 
572  /* Position of first subroutine word.
573  * 0 if there are no subroutines.
574  */
575  Uint32 m_first_sub_instruction_pos;
576 
577  /* The end of the buffer is used to store label and subroutine
578  * meta information used when resolving branches and calls when
579  * the program is finalised.
580  * As this meta information grows, the remaining words in the
581  * buffer may be less than buffer length minus the
582  * instructions length
583  */
584  Uint32 m_available_length;
585 
586  enum Flags {
587  /*
588  We will set m_got_error if an error occurs, so that we can
589  refuse to create an operation from InterpretedCode that the user
590  forgot to do error checks on.
591  */
592  GotError= 0x1,
593  /* Set if reading disk column. */
594  UsesDisk= 0x2,
595  /* Object state : Set if currently defining a subroutine */
596  InSubroutineDef= 0x4,
597  /* Has this program been finalised? */
598  Finalised= 0x8
599  };
600  Uint32 m_flags;
601 
602  NdbError m_error;
603 
604  enum InfoType {
605  Label = 0,
606  Subroutine = 1};
607 
608  /* Instances of this type are stored at the end of
609  * the buffer to describe label and subroutine
610  * positions. The instances are added as the labels and
611  * subroutines are defined, so the order (working backwards
612  * from the end of the buffer) would be :
613  *
614  * Main program labels (if any)
615  * First subroutine (if any)
616  * First subroutine label defs (if any)
617  * Second subroutine (if any)
618  * Second subroutine lable defs ....
619  *
620  * The subroutines should be in order of subroutine number
621  * as they must be defined in-order. The labels can be in
622  * any order.
623  *
624  * Before this information is used for finalisation, it is
625  * sorted so that the subroutines and labels are in-order.
626  */
627  struct CodeMetaInfo
628  {
629  Uint16 type;
630  Uint16 number; // Label or sub num
631  Uint16 firstInstrPos; // Offset from start of m_buffer, or
632  // from start of subs section for
633  // subs defs
634  };
635 
636  static const Uint32 CODEMETAINFO_WORDS = 2;
637 
638 
639  enum Errors
640  {
641  TooManyInstructions = 4518,
642  BadAttributeId = 4004,
643  BadLabelNum = 4226,
644  BranchToBadLabel = 4221,
645  BadLength = 4209,
646  BadSubNumber = 4227,
647  BadState = 4231
648  };
649 
650  int error(Uint32 code);
651  bool have_space_for(Uint32 wordsRequired);
652 
653  int add1(Uint32 x1);
654  int add2(Uint32 x1, Uint32 x2);
655  int add3(Uint32 x1, Uint32 x2, Uint32 x3);
656  int addN(Uint32 *data, Uint32 length);
657  int addMeta(CodeMetaInfo& info);
658 
659  int add_branch(Uint32 instruction, Uint32 Label);
660  int read_attr_impl(const NdbColumnImpl *c, Uint32 RegDest);
661  int write_attr_impl(const NdbColumnImpl *c, Uint32 RegSource);
662  int branch_col(Uint32 branch_type, Uint32 attrId, const void * val,
663  Uint32 len, Uint32 label);
664  int getInfo(Uint32 number, CodeMetaInfo &info) const;
665  static int compareMetaInfo(const void *a,
666  const void *b);
667 
668  NdbInterpretedCode(const NdbInterpretedCode&); // Not impl.
669  NdbInterpretedCode&operator=(const NdbInterpretedCode&);
670 };
671 #endif
672