1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[repr(u8)]
11#[allow(clippy::enum_variant_names)]
12pub enum Opcode {
13 Goto = 1,
16 Gosub = 2,
18 Return = 3,
20 InitCoroutine = 4,
22 EndCoroutine = 5,
24 Yield = 6,
26 HaltIfNull = 7,
28 Halt = 8,
30
31 Integer = 9,
34 Int64 = 10,
36 Real = 11,
38 String8 = 12,
40 String = 13,
42 BeginSubrtn = 14,
44 Null = 15,
46 SoftNull = 16,
48 Blob = 17,
50 Variable = 18,
52
53 Move = 19,
56 Copy = 20,
58 SCopy = 21,
60 IntCopy = 22,
62
63 FkCheck = 23,
66
67 ResultRow = 24,
70
71 Concat = 25,
74 Add = 26,
76 Subtract = 27,
78 Multiply = 28,
80 Divide = 29,
82 Remainder = 30,
84
85 CollSeq = 31,
88
89 BitAnd = 32,
92 BitOr = 33,
94 ShiftLeft = 34,
96 ShiftRight = 35,
98
99 AddImm = 36,
102 MustBeInt = 37,
104 RealAffinity = 38,
106 Cast = 39,
108
109 Eq = 40,
112 Ne = 41,
114 Lt = 42,
116 Le = 43,
118 Gt = 44,
120 Ge = 45,
122 ElseEq = 46,
124
125 Permutation = 47,
128 Compare = 48,
130
131 Jump = 49,
134 And = 50,
136 Or = 51,
138 IsTrue = 52,
140 Not = 53,
142 BitNot = 54,
144 Once = 55,
146 If = 56,
148 IfNot = 57,
150 IsNull = 58,
152 IsType = 59,
154 ZeroOrNull = 60,
156 NotNull = 61,
158 IfNullRow = 62,
160
161 Offset = 63,
164 Column = 64,
166 TypeCheck = 65,
168 Affinity = 66,
170
171 MakeRecord = 67,
174
175 Count = 68,
178
179 Savepoint = 69,
182 AutoCommit = 70,
184 Transaction = 71,
186
187 ReadCookie = 72,
190 SetCookie = 73,
192
193 ReopenIdx = 74,
196 OpenRead = 75,
198 OpenWrite = 76,
200 OpenDup = 77,
202 OpenEphemeral = 78,
204 OpenAutoindex = 79,
206 SorterOpen = 80,
208 SequenceTest = 81,
210 OpenPseudo = 82,
212 Close = 83,
214 ColumnsUsed = 84,
216
217 SeekLT = 85,
220 SeekLE = 86,
222 SeekGE = 87,
224 SeekGT = 88,
226 SeekScan = 89,
228 SeekHit = 90,
230 IfNotOpen = 91,
232
233 IfNoHope = 92,
236 NoConflict = 93,
238 NotFound = 94,
240 Found = 95,
242
243 SeekRowid = 96,
246 NotExists = 97,
248
249 Sequence = 98,
252 NewRowid = 99,
254
255 Insert = 100,
258 RowCell = 101,
260 Delete = 102,
262 ResetCount = 103,
264
265 SorterCompare = 104,
268 SorterData = 105,
270
271 RowData = 106,
274 Rowid = 107,
276 NullRow = 108,
278
279 SeekEnd = 109,
282 Last = 110,
284 IfSizeBetween = 111,
286 SorterSort = 112,
288 Sort = 113,
290 Rewind = 114,
292 IfEmpty = 115,
294
295 SorterNext = 116,
298 Prev = 117,
300 Next = 118,
302
303 IdxInsert = 119,
306 SorterInsert = 120,
308 IdxDelete = 121,
310
311 DeferredSeek = 122,
314 IdxRowid = 123,
316 FinishSeek = 124,
318
319 IdxLE = 125,
322 IdxGT = 126,
324 IdxLT = 127,
326 IdxGE = 128,
328
329 Destroy = 129,
332 Clear = 130,
334 ResetSorter = 131,
336 CreateBtree = 132,
338
339 SqlExec = 133,
342 ParseSchema = 134,
344 LoadAnalysis = 135,
346 DropTable = 136,
348 DropIndex = 137,
350 DropTrigger = 138,
352
353 IntegrityCk = 139,
356
357 RowSetAdd = 140,
360 RowSetRead = 141,
362 RowSetTest = 142,
364
365 Program = 143,
368 Param = 144,
370
371 FkCounter = 145,
374 FkIfZero = 146,
376
377 MemMax = 147,
380
381 IfPos = 148,
384 OffsetLimit = 149,
386 IfNotZero = 150,
388 DecrJumpZero = 151,
390
391 AggInverse = 152,
394 AggStep = 153,
396 AggStep1 = 154,
398 AggValue = 155,
400 AggFinal = 156,
402
403 Checkpoint = 157,
406 JournalMode = 158,
408
409 Vacuum = 159,
412 IncrVacuum = 160,
414
415 Expire = 161,
418 CursorLock = 162,
420 CursorUnlock = 163,
422 TableLock = 164,
424
425 VBegin = 165,
428 VCreate = 166,
430 VDestroy = 167,
432 VOpen = 168,
434 VCheck = 169,
436 VInitIn = 170,
438 VFilter = 171,
440 VColumn = 172,
442 VNext = 173,
444 VRename = 174,
446 VUpdate = 175,
448
449 Pagecount = 176,
452 MaxPgcnt = 177,
454
455 PureFunc = 178,
458 Function = 179,
460
461 ClrSubtype = 180,
464 GetSubtype = 181,
466 SetSubtype = 182,
468
469 FilterAdd = 183,
472 Filter = 184,
474
475 Trace = 185,
478 Init = 186,
480
481 CursorHint = 187,
484 Abortable = 188,
486 ReleaseReg = 189,
488
489 Noop = 190,
492}
493
494impl Opcode {
495 pub const COUNT: usize = 191;
497
498 #[allow(clippy::too_many_lines)]
500 pub const fn name(self) -> &'static str {
501 match self {
502 Self::Goto => "Goto",
503 Self::Gosub => "Gosub",
504 Self::Return => "Return",
505 Self::InitCoroutine => "InitCoroutine",
506 Self::EndCoroutine => "EndCoroutine",
507 Self::Yield => "Yield",
508 Self::HaltIfNull => "HaltIfNull",
509 Self::Halt => "Halt",
510 Self::Integer => "Integer",
511 Self::Int64 => "Int64",
512 Self::Real => "Real",
513 Self::String8 => "String8",
514 Self::String => "String",
515 Self::BeginSubrtn => "BeginSubrtn",
516 Self::Null => "Null",
517 Self::SoftNull => "SoftNull",
518 Self::Blob => "Blob",
519 Self::Variable => "Variable",
520 Self::Move => "Move",
521 Self::Copy => "Copy",
522 Self::SCopy => "SCopy",
523 Self::IntCopy => "IntCopy",
524 Self::FkCheck => "FkCheck",
525 Self::ResultRow => "ResultRow",
526 Self::Concat => "Concat",
527 Self::Add => "Add",
528 Self::Subtract => "Subtract",
529 Self::Multiply => "Multiply",
530 Self::Divide => "Divide",
531 Self::Remainder => "Remainder",
532 Self::CollSeq => "CollSeq",
533 Self::BitAnd => "BitAnd",
534 Self::BitOr => "BitOr",
535 Self::ShiftLeft => "ShiftLeft",
536 Self::ShiftRight => "ShiftRight",
537 Self::AddImm => "AddImm",
538 Self::MustBeInt => "MustBeInt",
539 Self::RealAffinity => "RealAffinity",
540 Self::Cast => "Cast",
541 Self::Eq => "Eq",
542 Self::Ne => "Ne",
543 Self::Lt => "Lt",
544 Self::Le => "Le",
545 Self::Gt => "Gt",
546 Self::Ge => "Ge",
547 Self::ElseEq => "ElseEq",
548 Self::Permutation => "Permutation",
549 Self::Compare => "Compare",
550 Self::Jump => "Jump",
551 Self::And => "And",
552 Self::Or => "Or",
553 Self::IsTrue => "IsTrue",
554 Self::Not => "Not",
555 Self::BitNot => "BitNot",
556 Self::Once => "Once",
557 Self::If => "If",
558 Self::IfNot => "IfNot",
559 Self::IsNull => "IsNull",
560 Self::IsType => "IsType",
561 Self::ZeroOrNull => "ZeroOrNull",
562 Self::NotNull => "NotNull",
563 Self::IfNullRow => "IfNullRow",
564 Self::Offset => "Offset",
565 Self::Column => "Column",
566 Self::TypeCheck => "TypeCheck",
567 Self::Affinity => "Affinity",
568 Self::MakeRecord => "MakeRecord",
569 Self::Count => "Count",
570 Self::Savepoint => "Savepoint",
571 Self::AutoCommit => "AutoCommit",
572 Self::Transaction => "Transaction",
573 Self::ReadCookie => "ReadCookie",
574 Self::SetCookie => "SetCookie",
575 Self::ReopenIdx => "ReopenIdx",
576 Self::OpenRead => "OpenRead",
577 Self::OpenWrite => "OpenWrite",
578 Self::OpenDup => "OpenDup",
579 Self::OpenEphemeral => "OpenEphemeral",
580 Self::OpenAutoindex => "OpenAutoindex",
581 Self::SorterOpen => "SorterOpen",
582 Self::SequenceTest => "SequenceTest",
583 Self::OpenPseudo => "OpenPseudo",
584 Self::Close => "Close",
585 Self::ColumnsUsed => "ColumnsUsed",
586 Self::SeekLT => "SeekLT",
587 Self::SeekLE => "SeekLE",
588 Self::SeekGE => "SeekGE",
589 Self::SeekGT => "SeekGT",
590 Self::SeekScan => "SeekScan",
591 Self::SeekHit => "SeekHit",
592 Self::IfNotOpen => "IfNotOpen",
593 Self::IfNoHope => "IfNoHope",
594 Self::NoConflict => "NoConflict",
595 Self::NotFound => "NotFound",
596 Self::Found => "Found",
597 Self::SeekRowid => "SeekRowid",
598 Self::NotExists => "NotExists",
599 Self::Sequence => "Sequence",
600 Self::NewRowid => "NewRowid",
601 Self::Insert => "Insert",
602 Self::RowCell => "RowCell",
603 Self::Delete => "Delete",
604 Self::ResetCount => "ResetCount",
605 Self::SorterCompare => "SorterCompare",
606 Self::SorterData => "SorterData",
607 Self::RowData => "RowData",
608 Self::Rowid => "Rowid",
609 Self::NullRow => "NullRow",
610 Self::SeekEnd => "SeekEnd",
611 Self::Last => "Last",
612 Self::IfSizeBetween => "IfSizeBetween",
613 Self::SorterSort => "SorterSort",
614 Self::Sort => "Sort",
615 Self::Rewind => "Rewind",
616 Self::IfEmpty => "IfEmpty",
617 Self::SorterNext => "SorterNext",
618 Self::Prev => "Prev",
619 Self::Next => "Next",
620 Self::IdxInsert => "IdxInsert",
621 Self::SorterInsert => "SorterInsert",
622 Self::IdxDelete => "IdxDelete",
623 Self::DeferredSeek => "DeferredSeek",
624 Self::IdxRowid => "IdxRowid",
625 Self::FinishSeek => "FinishSeek",
626 Self::IdxLE => "IdxLE",
627 Self::IdxGT => "IdxGT",
628 Self::IdxLT => "IdxLT",
629 Self::IdxGE => "IdxGE",
630 Self::Destroy => "Destroy",
631 Self::Clear => "Clear",
632 Self::ResetSorter => "ResetSorter",
633 Self::CreateBtree => "CreateBtree",
634 Self::SqlExec => "SqlExec",
635 Self::ParseSchema => "ParseSchema",
636 Self::LoadAnalysis => "LoadAnalysis",
637 Self::DropTable => "DropTable",
638 Self::DropIndex => "DropIndex",
639 Self::DropTrigger => "DropTrigger",
640 Self::IntegrityCk => "IntegrityCk",
641 Self::RowSetAdd => "RowSetAdd",
642 Self::RowSetRead => "RowSetRead",
643 Self::RowSetTest => "RowSetTest",
644 Self::Program => "Program",
645 Self::Param => "Param",
646 Self::FkCounter => "FkCounter",
647 Self::FkIfZero => "FkIfZero",
648 Self::MemMax => "MemMax",
649 Self::IfPos => "IfPos",
650 Self::OffsetLimit => "OffsetLimit",
651 Self::IfNotZero => "IfNotZero",
652 Self::DecrJumpZero => "DecrJumpZero",
653 Self::AggInverse => "AggInverse",
654 Self::AggStep => "AggStep",
655 Self::AggStep1 => "AggStep1",
656 Self::AggValue => "AggValue",
657 Self::AggFinal => "AggFinal",
658 Self::Checkpoint => "Checkpoint",
659 Self::JournalMode => "JournalMode",
660 Self::Vacuum => "Vacuum",
661 Self::IncrVacuum => "IncrVacuum",
662 Self::Expire => "Expire",
663 Self::CursorLock => "CursorLock",
664 Self::CursorUnlock => "CursorUnlock",
665 Self::TableLock => "TableLock",
666 Self::VBegin => "VBegin",
667 Self::VCreate => "VCreate",
668 Self::VDestroy => "VDestroy",
669 Self::VOpen => "VOpen",
670 Self::VCheck => "VCheck",
671 Self::VInitIn => "VInitIn",
672 Self::VFilter => "VFilter",
673 Self::VColumn => "VColumn",
674 Self::VNext => "VNext",
675 Self::VRename => "VRename",
676 Self::VUpdate => "VUpdate",
677 Self::Pagecount => "Pagecount",
678 Self::MaxPgcnt => "MaxPgcnt",
679 Self::PureFunc => "PureFunc",
680 Self::Function => "Function",
681 Self::ClrSubtype => "ClrSubtype",
682 Self::GetSubtype => "GetSubtype",
683 Self::SetSubtype => "SetSubtype",
684 Self::FilterAdd => "FilterAdd",
685 Self::Filter => "Filter",
686 Self::Trace => "Trace",
687 Self::Init => "Init",
688 Self::CursorHint => "CursorHint",
689 Self::Abortable => "Abortable",
690 Self::ReleaseReg => "ReleaseReg",
691 Self::Noop => "Noop",
692 }
693 }
694
695 #[allow(clippy::too_many_lines)]
697 pub const fn from_byte(byte: u8) -> Option<Self> {
698 if byte == 0 || byte > 190 {
699 return None;
700 }
701 match byte {
707 1 => Some(Self::Goto),
708 2 => Some(Self::Gosub),
709 3 => Some(Self::Return),
710 4 => Some(Self::InitCoroutine),
711 5 => Some(Self::EndCoroutine),
712 6 => Some(Self::Yield),
713 7 => Some(Self::HaltIfNull),
714 8 => Some(Self::Halt),
715 9 => Some(Self::Integer),
716 10 => Some(Self::Int64),
717 11 => Some(Self::Real),
718 12 => Some(Self::String8),
719 13 => Some(Self::String),
720 14 => Some(Self::BeginSubrtn),
721 15 => Some(Self::Null),
722 16 => Some(Self::SoftNull),
723 17 => Some(Self::Blob),
724 18 => Some(Self::Variable),
725 19 => Some(Self::Move),
726 20 => Some(Self::Copy),
727 21 => Some(Self::SCopy),
728 22 => Some(Self::IntCopy),
729 23 => Some(Self::FkCheck),
730 24 => Some(Self::ResultRow),
731 25 => Some(Self::Concat),
732 26 => Some(Self::Add),
733 27 => Some(Self::Subtract),
734 28 => Some(Self::Multiply),
735 29 => Some(Self::Divide),
736 30 => Some(Self::Remainder),
737 31 => Some(Self::CollSeq),
738 32 => Some(Self::BitAnd),
739 33 => Some(Self::BitOr),
740 34 => Some(Self::ShiftLeft),
741 35 => Some(Self::ShiftRight),
742 36 => Some(Self::AddImm),
743 37 => Some(Self::MustBeInt),
744 38 => Some(Self::RealAffinity),
745 39 => Some(Self::Cast),
746 40 => Some(Self::Eq),
747 41 => Some(Self::Ne),
748 42 => Some(Self::Lt),
749 43 => Some(Self::Le),
750 44 => Some(Self::Gt),
751 45 => Some(Self::Ge),
752 46 => Some(Self::ElseEq),
753 47 => Some(Self::Permutation),
754 48 => Some(Self::Compare),
755 49 => Some(Self::Jump),
756 50 => Some(Self::And),
757 51 => Some(Self::Or),
758 52 => Some(Self::IsTrue),
759 53 => Some(Self::Not),
760 54 => Some(Self::BitNot),
761 55 => Some(Self::Once),
762 56 => Some(Self::If),
763 57 => Some(Self::IfNot),
764 58 => Some(Self::IsNull),
765 59 => Some(Self::IsType),
766 60 => Some(Self::ZeroOrNull),
767 61 => Some(Self::NotNull),
768 62 => Some(Self::IfNullRow),
769 63 => Some(Self::Offset),
770 64 => Some(Self::Column),
771 65 => Some(Self::TypeCheck),
772 66 => Some(Self::Affinity),
773 67 => Some(Self::MakeRecord),
774 68 => Some(Self::Count),
775 69 => Some(Self::Savepoint),
776 70 => Some(Self::AutoCommit),
777 71 => Some(Self::Transaction),
778 72 => Some(Self::ReadCookie),
779 73 => Some(Self::SetCookie),
780 74 => Some(Self::ReopenIdx),
781 75 => Some(Self::OpenRead),
782 76 => Some(Self::OpenWrite),
783 77 => Some(Self::OpenDup),
784 78 => Some(Self::OpenEphemeral),
785 79 => Some(Self::OpenAutoindex),
786 80 => Some(Self::SorterOpen),
787 81 => Some(Self::SequenceTest),
788 82 => Some(Self::OpenPseudo),
789 83 => Some(Self::Close),
790 84 => Some(Self::ColumnsUsed),
791 85 => Some(Self::SeekLT),
792 86 => Some(Self::SeekLE),
793 87 => Some(Self::SeekGE),
794 88 => Some(Self::SeekGT),
795 89 => Some(Self::SeekScan),
796 90 => Some(Self::SeekHit),
797 91 => Some(Self::IfNotOpen),
798 92 => Some(Self::IfNoHope),
799 93 => Some(Self::NoConflict),
800 94 => Some(Self::NotFound),
801 95 => Some(Self::Found),
802 96 => Some(Self::SeekRowid),
803 97 => Some(Self::NotExists),
804 98 => Some(Self::Sequence),
805 99 => Some(Self::NewRowid),
806 100 => Some(Self::Insert),
807 101 => Some(Self::RowCell),
808 102 => Some(Self::Delete),
809 103 => Some(Self::ResetCount),
810 104 => Some(Self::SorterCompare),
811 105 => Some(Self::SorterData),
812 106 => Some(Self::RowData),
813 107 => Some(Self::Rowid),
814 108 => Some(Self::NullRow),
815 109 => Some(Self::SeekEnd),
816 110 => Some(Self::Last),
817 111 => Some(Self::IfSizeBetween),
818 112 => Some(Self::SorterSort),
819 113 => Some(Self::Sort),
820 114 => Some(Self::Rewind),
821 115 => Some(Self::IfEmpty),
822 116 => Some(Self::SorterNext),
823 117 => Some(Self::Prev),
824 118 => Some(Self::Next),
825 119 => Some(Self::IdxInsert),
826 120 => Some(Self::SorterInsert),
827 121 => Some(Self::IdxDelete),
828 122 => Some(Self::DeferredSeek),
829 123 => Some(Self::IdxRowid),
830 124 => Some(Self::FinishSeek),
831 125 => Some(Self::IdxLE),
832 126 => Some(Self::IdxGT),
833 127 => Some(Self::IdxLT),
834 128 => Some(Self::IdxGE),
835 129 => Some(Self::Destroy),
836 130 => Some(Self::Clear),
837 131 => Some(Self::ResetSorter),
838 132 => Some(Self::CreateBtree),
839 133 => Some(Self::SqlExec),
840 134 => Some(Self::ParseSchema),
841 135 => Some(Self::LoadAnalysis),
842 136 => Some(Self::DropTable),
843 137 => Some(Self::DropIndex),
844 138 => Some(Self::DropTrigger),
845 139 => Some(Self::IntegrityCk),
846 140 => Some(Self::RowSetAdd),
847 141 => Some(Self::RowSetRead),
848 142 => Some(Self::RowSetTest),
849 143 => Some(Self::Program),
850 144 => Some(Self::Param),
851 145 => Some(Self::FkCounter),
852 146 => Some(Self::FkIfZero),
853 147 => Some(Self::MemMax),
854 148 => Some(Self::IfPos),
855 149 => Some(Self::OffsetLimit),
856 150 => Some(Self::IfNotZero),
857 151 => Some(Self::DecrJumpZero),
858 152 => Some(Self::AggInverse),
859 153 => Some(Self::AggStep),
860 154 => Some(Self::AggStep1),
861 155 => Some(Self::AggValue),
862 156 => Some(Self::AggFinal),
863 157 => Some(Self::Checkpoint),
864 158 => Some(Self::JournalMode),
865 159 => Some(Self::Vacuum),
866 160 => Some(Self::IncrVacuum),
867 161 => Some(Self::Expire),
868 162 => Some(Self::CursorLock),
869 163 => Some(Self::CursorUnlock),
870 164 => Some(Self::TableLock),
871 165 => Some(Self::VBegin),
872 166 => Some(Self::VCreate),
873 167 => Some(Self::VDestroy),
874 168 => Some(Self::VOpen),
875 169 => Some(Self::VCheck),
876 170 => Some(Self::VInitIn),
877 171 => Some(Self::VFilter),
878 172 => Some(Self::VColumn),
879 173 => Some(Self::VNext),
880 174 => Some(Self::VRename),
881 175 => Some(Self::VUpdate),
882 176 => Some(Self::Pagecount),
883 177 => Some(Self::MaxPgcnt),
884 178 => Some(Self::PureFunc),
885 179 => Some(Self::Function),
886 180 => Some(Self::ClrSubtype),
887 181 => Some(Self::GetSubtype),
888 182 => Some(Self::SetSubtype),
889 183 => Some(Self::FilterAdd),
890 184 => Some(Self::Filter),
891 185 => Some(Self::Trace),
892 186 => Some(Self::Init),
893 187 => Some(Self::CursorHint),
894 188 => Some(Self::Abortable),
895 189 => Some(Self::ReleaseReg),
896 190 => Some(Self::Noop),
897 _ => None,
898 }
899 }
900
901 pub const fn is_jump(self) -> bool {
903 matches!(
904 self,
905 Self::Goto
906 | Self::Gosub
907 | Self::InitCoroutine
908 | Self::Yield
909 | Self::HaltIfNull
910 | Self::Once
911 | Self::If
912 | Self::IfNot
913 | Self::IsNull
914 | Self::IsType
915 | Self::NotNull
916 | Self::IfNullRow
917 | Self::Jump
918 | Self::Eq
919 | Self::Ne
920 | Self::Lt
921 | Self::Le
922 | Self::Gt
923 | Self::Ge
924 | Self::ElseEq
925 | Self::SeekLT
926 | Self::SeekLE
927 | Self::SeekGE
928 | Self::SeekGT
929 | Self::SeekRowid
930 | Self::NotExists
931 | Self::IfNotOpen
932 | Self::IfNoHope
933 | Self::NoConflict
934 | Self::NotFound
935 | Self::Found
936 | Self::Last
937 | Self::Rewind
938 | Self::IfEmpty
939 | Self::IfSizeBetween
940 | Self::Next
941 | Self::Prev
942 | Self::SorterNext
943 | Self::SorterSort
944 | Self::Sort
945 | Self::IdxLE
946 | Self::IdxGT
947 | Self::IdxLT
948 | Self::IdxGE
949 | Self::RowSetRead
950 | Self::RowSetTest
951 | Self::Program
952 | Self::FkIfZero
953 | Self::IfPos
954 | Self::IfNotZero
955 | Self::DecrJumpZero
956 | Self::IncrVacuum
957 | Self::VFilter
958 | Self::VNext
959 | Self::Filter
960 | Self::Init
961 )
962 }
963}
964
965impl std::fmt::Display for Opcode {
966 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
967 f.write_str(self.name())
968 }
969}
970
971#[derive(Debug, Clone, PartialEq)]
973pub struct VdbeOp {
974 pub opcode: Opcode,
976 pub p1: i32,
978 pub p2: i32,
980 pub p3: i32,
982 pub p4: P4,
984 pub p5: u16,
986}
987
988#[derive(Debug, Clone, PartialEq)]
993pub enum P4 {
994 None,
996 Int(i32),
998 Int64(i64),
1000 Real(f64),
1002 Str(String),
1004 Blob(Vec<u8>),
1006 Collation(String),
1008 FuncName(String),
1010 Table(String),
1012 Index(String),
1014 Affinity(String),
1016}
1017
1018use fsqlite_error::{FrankenError, Result};
1025
1026#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1032pub struct Label(u32);
1033
1034#[derive(Debug)]
1036enum LabelState {
1037 Unresolved(Vec<usize>),
1040 Resolved(i32),
1042}
1043
1044#[derive(Debug)]
1049pub struct RegisterAllocator {
1050 next_reg: i32,
1052 temp_pool: Vec<i32>,
1054}
1055
1056impl RegisterAllocator {
1057 #[must_use]
1059 pub fn new() -> Self {
1060 Self {
1061 next_reg: 1,
1062 temp_pool: Vec::new(),
1063 }
1064 }
1065
1066 pub fn alloc_reg(&mut self) -> i32 {
1068 let reg = self.next_reg;
1069 self.next_reg += 1;
1070 reg
1071 }
1072
1073 pub fn alloc_regs(&mut self, n: i32) -> i32 {
1077 let first = self.next_reg;
1078 self.next_reg += n;
1079 first
1080 }
1081
1082 pub fn alloc_temp(&mut self) -> i32 {
1084 self.temp_pool.pop().unwrap_or_else(|| {
1085 let reg = self.next_reg;
1086 self.next_reg += 1;
1087 reg
1088 })
1089 }
1090
1091 pub fn free_temp(&mut self, reg: i32) {
1093 self.temp_pool.push(reg);
1094 }
1095
1096 #[must_use]
1098 pub fn count(&self) -> i32 {
1099 self.next_reg - 1
1100 }
1101}
1102
1103impl Default for RegisterAllocator {
1104 fn default() -> Self {
1105 Self::new()
1106 }
1107}
1108
1109#[derive(Debug)]
1116pub struct ProgramBuilder {
1117 ops: Vec<VdbeOp>,
1119 labels: Vec<LabelState>,
1121 regs: RegisterAllocator,
1123}
1124
1125impl ProgramBuilder {
1126 #[must_use]
1128 pub fn new() -> Self {
1129 Self {
1130 ops: Vec::new(),
1131 labels: Vec::new(),
1132 regs: RegisterAllocator::new(),
1133 }
1134 }
1135
1136 pub fn emit(&mut self, op: VdbeOp) -> usize {
1140 let addr = self.ops.len();
1141 self.ops.push(op);
1142 addr
1143 }
1144
1145 pub fn emit_op(&mut self, opcode: Opcode, p1: i32, p2: i32, p3: i32, p4: P4, p5: u16) -> usize {
1147 self.emit(VdbeOp {
1148 opcode,
1149 p1,
1150 p2,
1151 p3,
1152 p4,
1153 p5,
1154 })
1155 }
1156
1157 #[must_use]
1159 pub fn current_addr(&self) -> usize {
1160 self.ops.len()
1161 }
1162
1163 #[must_use]
1165 pub fn op_at(&self, addr: usize) -> Option<&VdbeOp> {
1166 self.ops.get(addr)
1167 }
1168
1169 #[must_use]
1171 pub fn op_at_mut(&mut self, addr: usize) -> Option<&mut VdbeOp> {
1172 self.ops.get_mut(addr)
1173 }
1174
1175 #[must_use]
1179 pub fn emit_label(&mut self) -> Label {
1180 let id = u32::try_from(self.labels.len()).expect("too many labels");
1181 self.labels.push(LabelState::Unresolved(Vec::new()));
1182 Label(id)
1183 }
1184
1185 pub fn emit_jump_to_label(
1189 &mut self,
1190 opcode: Opcode,
1191 p1: i32,
1192 p3: i32,
1193 label: Label,
1194 p4: P4,
1195 p5: u16,
1196 ) -> usize {
1197 let addr = self.emit(VdbeOp {
1198 opcode,
1199 p1,
1200 p2: -1, p3,
1202 p4,
1203 p5,
1204 });
1205
1206 let state = self
1207 .labels
1208 .get_mut(usize::try_from(label.0).expect("label fits usize"))
1209 .expect("label must exist");
1210
1211 match state {
1212 LabelState::Unresolved(refs) => refs.push(addr),
1213 LabelState::Resolved(target) => {
1214 self.ops[addr].p2 = *target;
1216 }
1217 }
1218
1219 addr
1220 }
1221
1222 pub fn resolve_label(&mut self, label: Label) {
1224 let addr = i32::try_from(self.current_addr()).expect("program too large");
1225 self.resolve_label_to(label, addr);
1226 }
1227
1228 pub fn resolve_label_to(&mut self, label: Label, address: i32) {
1230 let idx = usize::try_from(label.0).expect("label fits usize");
1231 let state = self.labels.get_mut(idx).expect("label must exist");
1232
1233 match state {
1234 LabelState::Unresolved(refs) => {
1235 for &ref_addr in refs.iter() {
1237 self.ops[ref_addr].p2 = address;
1238 }
1239 *state = LabelState::Resolved(address);
1240 }
1241 LabelState::Resolved(_) => {
1242 *state = LabelState::Resolved(address);
1244 }
1245 }
1246 }
1247
1248 pub fn alloc_reg(&mut self) -> i32 {
1252 self.regs.alloc_reg()
1253 }
1254
1255 pub fn alloc_regs(&mut self, n: i32) -> i32 {
1257 self.regs.alloc_regs(n)
1258 }
1259
1260 pub fn alloc_temp(&mut self) -> i32 {
1262 self.regs.alloc_temp()
1263 }
1264
1265 pub fn free_temp(&mut self, reg: i32) {
1267 self.regs.free_temp(reg);
1268 }
1269
1270 #[must_use]
1272 pub fn register_count(&self) -> i32 {
1273 self.regs.count()
1274 }
1275
1276 pub fn finish(self) -> Result<VdbeProgram> {
1280 for (i, state) in self.labels.iter().enumerate() {
1282 if let LabelState::Unresolved(refs) = state {
1283 if !refs.is_empty() {
1284 return Err(FrankenError::Internal(format!(
1285 "unresolved label {i} referenced by {} instruction(s)",
1286 refs.len()
1287 )));
1288 }
1289 }
1290 }
1291
1292 Ok(VdbeProgram {
1293 ops: self.ops,
1294 register_count: self.regs.count(),
1295 })
1296 }
1297}
1298
1299impl Default for ProgramBuilder {
1300 fn default() -> Self {
1301 Self::new()
1302 }
1303}
1304
1305#[derive(Debug, Clone, PartialEq)]
1307pub struct VdbeProgram {
1308 ops: Vec<VdbeOp>,
1310 register_count: i32,
1312}
1313
1314impl VdbeProgram {
1315 #[must_use]
1317 pub fn ops(&self) -> &[VdbeOp] {
1318 &self.ops
1319 }
1320
1321 #[must_use]
1323 pub fn len(&self) -> usize {
1324 self.ops.len()
1325 }
1326
1327 #[must_use]
1329 pub fn is_empty(&self) -> bool {
1330 self.ops.is_empty()
1331 }
1332
1333 #[must_use]
1335 pub fn register_count(&self) -> i32 {
1336 self.register_count
1337 }
1338
1339 #[must_use]
1341 pub fn get(&self, pc: usize) -> Option<&VdbeOp> {
1342 self.ops.get(pc)
1343 }
1344
1345 #[must_use]
1349 pub fn disassemble(&self) -> String {
1350 use std::fmt::Write;
1351
1352 let mut out = std::string::String::with_capacity(self.ops.len() * 60);
1353 out.push_str("addr opcode p1 p2 p3 p4 p5\n");
1354 out.push_str("---- --------------- ---- ---- ---- ----------------- --\n");
1355
1356 for (addr, op) in self.ops.iter().enumerate() {
1357 let p4_str = match &op.p4 {
1358 P4::None => String::new(),
1359 P4::Int(v) => format!("(int){v}"),
1360 P4::Int64(v) => format!("(i64){v}"),
1361 P4::Real(v) => format!("(real){v}"),
1362 P4::Str(s) => format!("(str){s}"),
1363 P4::Blob(b) => format!("(blob)[{}B]", b.len()),
1364 P4::Collation(c) => format!("(coll){c}"),
1365 P4::FuncName(f) => format!("(func){f}"),
1366 P4::Table(t) => format!("(tbl){t}"),
1367 P4::Index(i) => format!("(idx){i}"),
1368 P4::Affinity(a) => format!("(aff){a}"),
1369 };
1370
1371 writeln!(
1372 &mut out,
1373 "{addr:<4} {:<15} {:<4} {:<4} {:<4} {:<17} {:<2}",
1374 op.opcode.name(),
1375 op.p1,
1376 op.p2,
1377 op.p3,
1378 p4_str,
1379 op.p5,
1380 )
1381 .expect("write to string");
1382 }
1383
1384 out
1385 }
1386}
1387
1388#[cfg(test)]
1389#[allow(clippy::approx_constant)]
1390mod tests {
1391 use super::*;
1392 use std::collections::HashSet;
1393
1394 #[test]
1395 fn opcode_count() {
1396 assert_eq!(Opcode::COUNT, 191);
1397 }
1398
1399 #[test]
1400 fn opcode_name_roundtrip() {
1401 assert_eq!(Opcode::Goto.name(), "Goto");
1403 assert_eq!(Opcode::Halt.name(), "Halt");
1404 assert_eq!(Opcode::Insert.name(), "Insert");
1405 assert_eq!(Opcode::Delete.name(), "Delete");
1406 assert_eq!(Opcode::ResultRow.name(), "ResultRow");
1407 assert_eq!(Opcode::Noop.name(), "Noop");
1408 }
1409
1410 #[test]
1411 fn opcode_from_byte() {
1412 assert_eq!(Opcode::from_byte(0), None);
1413 assert_eq!(Opcode::from_byte(1), Some(Opcode::Goto));
1414 assert_eq!(Opcode::from_byte(8), Some(Opcode::Halt));
1415 assert_eq!(Opcode::from_byte(190), Some(Opcode::Noop));
1416 assert_eq!(Opcode::from_byte(191), None);
1417 assert_eq!(Opcode::from_byte(255), None);
1418 }
1419
1420 #[test]
1421 fn opcode_from_byte_exhaustive() {
1422 for i in 1..=190u8 {
1424 assert!(
1425 Opcode::from_byte(i).is_some(),
1426 "from_byte({i}) returned None"
1427 );
1428 }
1429 }
1430
1431 #[test]
1432 fn test_opcode_distinct_u8_values() {
1433 let mut encoded = HashSet::new();
1434 for byte in 1..=190_u8 {
1435 let opcode = Opcode::from_byte(byte).expect("opcode byte must decode");
1436 let inserted = encoded.insert(opcode as u8);
1437 assert!(inserted, "duplicate opcode byte value for {:?}", opcode);
1438 }
1439
1440 assert_eq!(encoded.len(), 190, "every opcode must map to a unique byte");
1441 }
1442
1443 #[test]
1444 fn opcode_display() {
1445 assert_eq!(Opcode::Goto.to_string(), "Goto");
1446 assert_eq!(Opcode::Init.to_string(), "Init");
1447 }
1448
1449 #[test]
1450 fn opcode_is_jump() {
1451 assert!(Opcode::Goto.is_jump());
1452 assert!(Opcode::If.is_jump());
1453 assert!(Opcode::IfNot.is_jump());
1454 assert!(Opcode::Eq.is_jump());
1455 assert!(Opcode::Next.is_jump());
1456 assert!(Opcode::Rewind.is_jump());
1457 assert!(Opcode::Init.is_jump());
1458
1459 assert!(!Opcode::Integer.is_jump());
1460 assert!(!Opcode::Add.is_jump());
1461 assert!(!Opcode::Insert.is_jump());
1462 assert!(!Opcode::Noop.is_jump());
1463 assert!(!Opcode::ResultRow.is_jump());
1464 }
1465
1466 #[test]
1467 fn vdbe_op_basic() {
1468 let op = VdbeOp {
1469 opcode: Opcode::Integer,
1470 p1: 42,
1471 p2: 1,
1472 p3: 0,
1473 p4: P4::None,
1474 p5: 0,
1475 };
1476 assert_eq!(op.opcode, Opcode::Integer);
1477 assert_eq!(op.p1, 42);
1478 }
1479
1480 #[test]
1481 fn p4_variants() {
1482 let p4 = P4::Int(42);
1483 assert_eq!(p4, P4::Int(42));
1484
1485 let p4 = P4::Str("hello".to_owned());
1486 assert_eq!(p4, P4::Str("hello".to_owned()));
1487
1488 let p4 = P4::Real(3.14);
1489 assert_eq!(p4, P4::Real(3.14));
1490 }
1491}