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 SetSnapshot = 190,
495
496 Noop = 191,
499}
500
501impl Opcode {
502 pub const COUNT: usize = 192;
504
505 #[allow(clippy::too_many_lines)]
507 pub const fn name(self) -> &'static str {
508 match self {
509 Self::Goto => "Goto",
510 Self::Gosub => "Gosub",
511 Self::Return => "Return",
512 Self::InitCoroutine => "InitCoroutine",
513 Self::EndCoroutine => "EndCoroutine",
514 Self::Yield => "Yield",
515 Self::HaltIfNull => "HaltIfNull",
516 Self::Halt => "Halt",
517 Self::Integer => "Integer",
518 Self::Int64 => "Int64",
519 Self::Real => "Real",
520 Self::String8 => "String8",
521 Self::String => "String",
522 Self::BeginSubrtn => "BeginSubrtn",
523 Self::Null => "Null",
524 Self::SoftNull => "SoftNull",
525 Self::Blob => "Blob",
526 Self::Variable => "Variable",
527 Self::Move => "Move",
528 Self::Copy => "Copy",
529 Self::SCopy => "SCopy",
530 Self::IntCopy => "IntCopy",
531 Self::FkCheck => "FkCheck",
532 Self::ResultRow => "ResultRow",
533 Self::Concat => "Concat",
534 Self::Add => "Add",
535 Self::Subtract => "Subtract",
536 Self::Multiply => "Multiply",
537 Self::Divide => "Divide",
538 Self::Remainder => "Remainder",
539 Self::CollSeq => "CollSeq",
540 Self::BitAnd => "BitAnd",
541 Self::BitOr => "BitOr",
542 Self::ShiftLeft => "ShiftLeft",
543 Self::ShiftRight => "ShiftRight",
544 Self::AddImm => "AddImm",
545 Self::MustBeInt => "MustBeInt",
546 Self::RealAffinity => "RealAffinity",
547 Self::Cast => "Cast",
548 Self::Eq => "Eq",
549 Self::Ne => "Ne",
550 Self::Lt => "Lt",
551 Self::Le => "Le",
552 Self::Gt => "Gt",
553 Self::Ge => "Ge",
554 Self::ElseEq => "ElseEq",
555 Self::Permutation => "Permutation",
556 Self::Compare => "Compare",
557 Self::Jump => "Jump",
558 Self::And => "And",
559 Self::Or => "Or",
560 Self::IsTrue => "IsTrue",
561 Self::Not => "Not",
562 Self::BitNot => "BitNot",
563 Self::Once => "Once",
564 Self::If => "If",
565 Self::IfNot => "IfNot",
566 Self::IsNull => "IsNull",
567 Self::IsType => "IsType",
568 Self::ZeroOrNull => "ZeroOrNull",
569 Self::NotNull => "NotNull",
570 Self::IfNullRow => "IfNullRow",
571 Self::Offset => "Offset",
572 Self::Column => "Column",
573 Self::TypeCheck => "TypeCheck",
574 Self::Affinity => "Affinity",
575 Self::MakeRecord => "MakeRecord",
576 Self::Count => "Count",
577 Self::Savepoint => "Savepoint",
578 Self::AutoCommit => "AutoCommit",
579 Self::Transaction => "Transaction",
580 Self::ReadCookie => "ReadCookie",
581 Self::SetCookie => "SetCookie",
582 Self::ReopenIdx => "ReopenIdx",
583 Self::OpenRead => "OpenRead",
584 Self::OpenWrite => "OpenWrite",
585 Self::OpenDup => "OpenDup",
586 Self::OpenEphemeral => "OpenEphemeral",
587 Self::OpenAutoindex => "OpenAutoindex",
588 Self::SorterOpen => "SorterOpen",
589 Self::SequenceTest => "SequenceTest",
590 Self::OpenPseudo => "OpenPseudo",
591 Self::Close => "Close",
592 Self::ColumnsUsed => "ColumnsUsed",
593 Self::SeekLT => "SeekLT",
594 Self::SeekLE => "SeekLE",
595 Self::SeekGE => "SeekGE",
596 Self::SeekGT => "SeekGT",
597 Self::SeekScan => "SeekScan",
598 Self::SeekHit => "SeekHit",
599 Self::IfNotOpen => "IfNotOpen",
600 Self::IfNoHope => "IfNoHope",
601 Self::NoConflict => "NoConflict",
602 Self::NotFound => "NotFound",
603 Self::Found => "Found",
604 Self::SeekRowid => "SeekRowid",
605 Self::NotExists => "NotExists",
606 Self::Sequence => "Sequence",
607 Self::NewRowid => "NewRowid",
608 Self::Insert => "Insert",
609 Self::RowCell => "RowCell",
610 Self::Delete => "Delete",
611 Self::ResetCount => "ResetCount",
612 Self::SorterCompare => "SorterCompare",
613 Self::SorterData => "SorterData",
614 Self::RowData => "RowData",
615 Self::Rowid => "Rowid",
616 Self::NullRow => "NullRow",
617 Self::SeekEnd => "SeekEnd",
618 Self::Last => "Last",
619 Self::IfSizeBetween => "IfSizeBetween",
620 Self::SorterSort => "SorterSort",
621 Self::Sort => "Sort",
622 Self::Rewind => "Rewind",
623 Self::IfEmpty => "IfEmpty",
624 Self::SorterNext => "SorterNext",
625 Self::Prev => "Prev",
626 Self::Next => "Next",
627 Self::IdxInsert => "IdxInsert",
628 Self::SorterInsert => "SorterInsert",
629 Self::IdxDelete => "IdxDelete",
630 Self::DeferredSeek => "DeferredSeek",
631 Self::IdxRowid => "IdxRowid",
632 Self::FinishSeek => "FinishSeek",
633 Self::IdxLE => "IdxLE",
634 Self::IdxGT => "IdxGT",
635 Self::IdxLT => "IdxLT",
636 Self::IdxGE => "IdxGE",
637 Self::Destroy => "Destroy",
638 Self::Clear => "Clear",
639 Self::ResetSorter => "ResetSorter",
640 Self::CreateBtree => "CreateBtree",
641 Self::SqlExec => "SqlExec",
642 Self::ParseSchema => "ParseSchema",
643 Self::LoadAnalysis => "LoadAnalysis",
644 Self::DropTable => "DropTable",
645 Self::DropIndex => "DropIndex",
646 Self::DropTrigger => "DropTrigger",
647 Self::IntegrityCk => "IntegrityCk",
648 Self::RowSetAdd => "RowSetAdd",
649 Self::RowSetRead => "RowSetRead",
650 Self::RowSetTest => "RowSetTest",
651 Self::Program => "Program",
652 Self::Param => "Param",
653 Self::FkCounter => "FkCounter",
654 Self::FkIfZero => "FkIfZero",
655 Self::MemMax => "MemMax",
656 Self::IfPos => "IfPos",
657 Self::OffsetLimit => "OffsetLimit",
658 Self::IfNotZero => "IfNotZero",
659 Self::DecrJumpZero => "DecrJumpZero",
660 Self::AggInverse => "AggInverse",
661 Self::AggStep => "AggStep",
662 Self::AggStep1 => "AggStep1",
663 Self::AggValue => "AggValue",
664 Self::AggFinal => "AggFinal",
665 Self::Checkpoint => "Checkpoint",
666 Self::JournalMode => "JournalMode",
667 Self::Vacuum => "Vacuum",
668 Self::IncrVacuum => "IncrVacuum",
669 Self::Expire => "Expire",
670 Self::CursorLock => "CursorLock",
671 Self::CursorUnlock => "CursorUnlock",
672 Self::TableLock => "TableLock",
673 Self::VBegin => "VBegin",
674 Self::VCreate => "VCreate",
675 Self::VDestroy => "VDestroy",
676 Self::VOpen => "VOpen",
677 Self::VCheck => "VCheck",
678 Self::VInitIn => "VInitIn",
679 Self::VFilter => "VFilter",
680 Self::VColumn => "VColumn",
681 Self::VNext => "VNext",
682 Self::VRename => "VRename",
683 Self::VUpdate => "VUpdate",
684 Self::Pagecount => "Pagecount",
685 Self::MaxPgcnt => "MaxPgcnt",
686 Self::PureFunc => "PureFunc",
687 Self::Function => "Function",
688 Self::ClrSubtype => "ClrSubtype",
689 Self::GetSubtype => "GetSubtype",
690 Self::SetSubtype => "SetSubtype",
691 Self::FilterAdd => "FilterAdd",
692 Self::Filter => "Filter",
693 Self::Trace => "Trace",
694 Self::Init => "Init",
695 Self::CursorHint => "CursorHint",
696 Self::Abortable => "Abortable",
697 Self::ReleaseReg => "ReleaseReg",
698 Self::SetSnapshot => "SetSnapshot",
699 Self::Noop => "Noop",
700 }
701 }
702
703 #[allow(clippy::too_many_lines)]
705 pub const fn from_byte(byte: u8) -> Option<Self> {
706 if byte == 0 || byte > 191 {
707 return None;
708 }
709 match byte {
715 1 => Some(Self::Goto),
716 2 => Some(Self::Gosub),
717 3 => Some(Self::Return),
718 4 => Some(Self::InitCoroutine),
719 5 => Some(Self::EndCoroutine),
720 6 => Some(Self::Yield),
721 7 => Some(Self::HaltIfNull),
722 8 => Some(Self::Halt),
723 9 => Some(Self::Integer),
724 10 => Some(Self::Int64),
725 11 => Some(Self::Real),
726 12 => Some(Self::String8),
727 13 => Some(Self::String),
728 14 => Some(Self::BeginSubrtn),
729 15 => Some(Self::Null),
730 16 => Some(Self::SoftNull),
731 17 => Some(Self::Blob),
732 18 => Some(Self::Variable),
733 19 => Some(Self::Move),
734 20 => Some(Self::Copy),
735 21 => Some(Self::SCopy),
736 22 => Some(Self::IntCopy),
737 23 => Some(Self::FkCheck),
738 24 => Some(Self::ResultRow),
739 25 => Some(Self::Concat),
740 26 => Some(Self::Add),
741 27 => Some(Self::Subtract),
742 28 => Some(Self::Multiply),
743 29 => Some(Self::Divide),
744 30 => Some(Self::Remainder),
745 31 => Some(Self::CollSeq),
746 32 => Some(Self::BitAnd),
747 33 => Some(Self::BitOr),
748 34 => Some(Self::ShiftLeft),
749 35 => Some(Self::ShiftRight),
750 36 => Some(Self::AddImm),
751 37 => Some(Self::MustBeInt),
752 38 => Some(Self::RealAffinity),
753 39 => Some(Self::Cast),
754 40 => Some(Self::Eq),
755 41 => Some(Self::Ne),
756 42 => Some(Self::Lt),
757 43 => Some(Self::Le),
758 44 => Some(Self::Gt),
759 45 => Some(Self::Ge),
760 46 => Some(Self::ElseEq),
761 47 => Some(Self::Permutation),
762 48 => Some(Self::Compare),
763 49 => Some(Self::Jump),
764 50 => Some(Self::And),
765 51 => Some(Self::Or),
766 52 => Some(Self::IsTrue),
767 53 => Some(Self::Not),
768 54 => Some(Self::BitNot),
769 55 => Some(Self::Once),
770 56 => Some(Self::If),
771 57 => Some(Self::IfNot),
772 58 => Some(Self::IsNull),
773 59 => Some(Self::IsType),
774 60 => Some(Self::ZeroOrNull),
775 61 => Some(Self::NotNull),
776 62 => Some(Self::IfNullRow),
777 63 => Some(Self::Offset),
778 64 => Some(Self::Column),
779 65 => Some(Self::TypeCheck),
780 66 => Some(Self::Affinity),
781 67 => Some(Self::MakeRecord),
782 68 => Some(Self::Count),
783 69 => Some(Self::Savepoint),
784 70 => Some(Self::AutoCommit),
785 71 => Some(Self::Transaction),
786 72 => Some(Self::ReadCookie),
787 73 => Some(Self::SetCookie),
788 74 => Some(Self::ReopenIdx),
789 75 => Some(Self::OpenRead),
790 76 => Some(Self::OpenWrite),
791 77 => Some(Self::OpenDup),
792 78 => Some(Self::OpenEphemeral),
793 79 => Some(Self::OpenAutoindex),
794 80 => Some(Self::SorterOpen),
795 81 => Some(Self::SequenceTest),
796 82 => Some(Self::OpenPseudo),
797 83 => Some(Self::Close),
798 84 => Some(Self::ColumnsUsed),
799 85 => Some(Self::SeekLT),
800 86 => Some(Self::SeekLE),
801 87 => Some(Self::SeekGE),
802 88 => Some(Self::SeekGT),
803 89 => Some(Self::SeekScan),
804 90 => Some(Self::SeekHit),
805 91 => Some(Self::IfNotOpen),
806 92 => Some(Self::IfNoHope),
807 93 => Some(Self::NoConflict),
808 94 => Some(Self::NotFound),
809 95 => Some(Self::Found),
810 96 => Some(Self::SeekRowid),
811 97 => Some(Self::NotExists),
812 98 => Some(Self::Sequence),
813 99 => Some(Self::NewRowid),
814 100 => Some(Self::Insert),
815 101 => Some(Self::RowCell),
816 102 => Some(Self::Delete),
817 103 => Some(Self::ResetCount),
818 104 => Some(Self::SorterCompare),
819 105 => Some(Self::SorterData),
820 106 => Some(Self::RowData),
821 107 => Some(Self::Rowid),
822 108 => Some(Self::NullRow),
823 109 => Some(Self::SeekEnd),
824 110 => Some(Self::Last),
825 111 => Some(Self::IfSizeBetween),
826 112 => Some(Self::SorterSort),
827 113 => Some(Self::Sort),
828 114 => Some(Self::Rewind),
829 115 => Some(Self::IfEmpty),
830 116 => Some(Self::SorterNext),
831 117 => Some(Self::Prev),
832 118 => Some(Self::Next),
833 119 => Some(Self::IdxInsert),
834 120 => Some(Self::SorterInsert),
835 121 => Some(Self::IdxDelete),
836 122 => Some(Self::DeferredSeek),
837 123 => Some(Self::IdxRowid),
838 124 => Some(Self::FinishSeek),
839 125 => Some(Self::IdxLE),
840 126 => Some(Self::IdxGT),
841 127 => Some(Self::IdxLT),
842 128 => Some(Self::IdxGE),
843 129 => Some(Self::Destroy),
844 130 => Some(Self::Clear),
845 131 => Some(Self::ResetSorter),
846 132 => Some(Self::CreateBtree),
847 133 => Some(Self::SqlExec),
848 134 => Some(Self::ParseSchema),
849 135 => Some(Self::LoadAnalysis),
850 136 => Some(Self::DropTable),
851 137 => Some(Self::DropIndex),
852 138 => Some(Self::DropTrigger),
853 139 => Some(Self::IntegrityCk),
854 140 => Some(Self::RowSetAdd),
855 141 => Some(Self::RowSetRead),
856 142 => Some(Self::RowSetTest),
857 143 => Some(Self::Program),
858 144 => Some(Self::Param),
859 145 => Some(Self::FkCounter),
860 146 => Some(Self::FkIfZero),
861 147 => Some(Self::MemMax),
862 148 => Some(Self::IfPos),
863 149 => Some(Self::OffsetLimit),
864 150 => Some(Self::IfNotZero),
865 151 => Some(Self::DecrJumpZero),
866 152 => Some(Self::AggInverse),
867 153 => Some(Self::AggStep),
868 154 => Some(Self::AggStep1),
869 155 => Some(Self::AggValue),
870 156 => Some(Self::AggFinal),
871 157 => Some(Self::Checkpoint),
872 158 => Some(Self::JournalMode),
873 159 => Some(Self::Vacuum),
874 160 => Some(Self::IncrVacuum),
875 161 => Some(Self::Expire),
876 162 => Some(Self::CursorLock),
877 163 => Some(Self::CursorUnlock),
878 164 => Some(Self::TableLock),
879 165 => Some(Self::VBegin),
880 166 => Some(Self::VCreate),
881 167 => Some(Self::VDestroy),
882 168 => Some(Self::VOpen),
883 169 => Some(Self::VCheck),
884 170 => Some(Self::VInitIn),
885 171 => Some(Self::VFilter),
886 172 => Some(Self::VColumn),
887 173 => Some(Self::VNext),
888 174 => Some(Self::VRename),
889 175 => Some(Self::VUpdate),
890 176 => Some(Self::Pagecount),
891 177 => Some(Self::MaxPgcnt),
892 178 => Some(Self::PureFunc),
893 179 => Some(Self::Function),
894 180 => Some(Self::ClrSubtype),
895 181 => Some(Self::GetSubtype),
896 182 => Some(Self::SetSubtype),
897 183 => Some(Self::FilterAdd),
898 184 => Some(Self::Filter),
899 185 => Some(Self::Trace),
900 186 => Some(Self::Init),
901 187 => Some(Self::CursorHint),
902 188 => Some(Self::Abortable),
903 189 => Some(Self::ReleaseReg),
904 190 => Some(Self::SetSnapshot),
905 191 => Some(Self::Noop),
906 _ => None,
907 }
908 }
909
910 pub const fn is_jump(self) -> bool {
912 matches!(
913 self,
914 Self::Goto
915 | Self::Gosub
916 | Self::InitCoroutine
917 | Self::Yield
918 | Self::HaltIfNull
919 | Self::Once
920 | Self::If
921 | Self::IfNot
922 | Self::IsNull
923 | Self::IsType
924 | Self::NotNull
925 | Self::IfNullRow
926 | Self::Jump
927 | Self::Eq
928 | Self::Ne
929 | Self::Lt
930 | Self::Le
931 | Self::Gt
932 | Self::Ge
933 | Self::ElseEq
934 | Self::SeekLT
935 | Self::SeekLE
936 | Self::SeekGE
937 | Self::SeekGT
938 | Self::SeekRowid
939 | Self::NotExists
940 | Self::IfNotOpen
941 | Self::IfNoHope
942 | Self::NoConflict
943 | Self::NotFound
944 | Self::Found
945 | Self::Last
946 | Self::Rewind
947 | Self::IfEmpty
948 | Self::IfSizeBetween
949 | Self::Next
950 | Self::Prev
951 | Self::SorterNext
952 | Self::SorterSort
953 | Self::Sort
954 | Self::IdxLE
955 | Self::IdxGT
956 | Self::IdxLT
957 | Self::IdxGE
958 | Self::RowSetRead
959 | Self::RowSetTest
960 | Self::Program
961 | Self::FkIfZero
962 | Self::IfPos
963 | Self::IfNotZero
964 | Self::DecrJumpZero
965 | Self::IncrVacuum
966 | Self::VFilter
967 | Self::VNext
968 | Self::Filter
969 | Self::Init
970 )
971 }
972}
973
974impl std::fmt::Display for Opcode {
975 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
976 f.write_str(self.name())
977 }
978}
979
980#[derive(Debug, Clone, PartialEq)]
982pub struct VdbeOp {
983 pub opcode: Opcode,
985 pub p1: i32,
987 pub p2: i32,
989 pub p3: i32,
991 pub p4: P4,
993 pub p5: u16,
995}
996
997#[derive(Debug, Clone, PartialEq, Eq)]
1002pub struct IndexCursorMeta {
1003 pub cursor_id: i32,
1005 pub column_indices: Vec<usize>,
1008}
1009
1010#[derive(Debug, Clone, PartialEq)]
1015pub enum P4 {
1016 None,
1018 Int(i32),
1020 Int64(i64),
1022 Real(f64),
1024 Str(String),
1026 Blob(Vec<u8>),
1028 Collation(String),
1030 FuncName(String),
1032 FuncNameCollated(String, String),
1036 Table(String),
1038 Index(String),
1040 Affinity(String),
1042 TimeTravelCommitSeq(u64),
1044 TimeTravelTimestamp(String),
1046}
1047
1048use fsqlite_error::{FrankenError, Result};
1055use smallvec::SmallVec;
1056
1057#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1063pub struct Label(u32);
1064
1065#[derive(Debug)]
1067enum LabelState {
1068 Unresolved(Vec<usize>),
1071 Resolved(i32),
1073}
1074
1075#[derive(Debug)]
1080pub struct RegisterAllocator {
1081 next_reg: i32,
1083 temp_pool: Vec<i32>,
1085}
1086
1087impl RegisterAllocator {
1088 #[must_use]
1090 pub fn new() -> Self {
1091 Self {
1092 next_reg: 1,
1093 temp_pool: Vec::new(),
1094 }
1095 }
1096
1097 pub fn alloc_reg(&mut self) -> i32 {
1099 let reg = self.next_reg;
1100 self.next_reg += 1;
1101 reg
1102 }
1103
1104 pub fn alloc_regs(&mut self, n: i32) -> i32 {
1108 let first = self.next_reg;
1109 self.next_reg += n;
1110 first
1111 }
1112
1113 pub fn alloc_temp(&mut self) -> i32 {
1115 self.temp_pool.pop().unwrap_or_else(|| {
1116 let reg = self.next_reg;
1117 self.next_reg += 1;
1118 reg
1119 })
1120 }
1121
1122 pub fn free_temp(&mut self, reg: i32) {
1124 self.temp_pool.push(reg);
1125 }
1126
1127 #[must_use]
1129 pub fn count(&self) -> i32 {
1130 self.next_reg - 1
1131 }
1132}
1133
1134impl Default for RegisterAllocator {
1135 fn default() -> Self {
1136 Self::new()
1137 }
1138}
1139
1140#[derive(Debug)]
1147pub struct ProgramBuilder {
1148 ops: SmallVec<[VdbeOp; 64]>,
1150 labels: Vec<LabelState>,
1152 regs: RegisterAllocator,
1154}
1155
1156impl ProgramBuilder {
1157 #[must_use]
1159 pub fn new() -> Self {
1160 Self {
1161 ops: SmallVec::new(),
1162 labels: Vec::new(),
1163 regs: RegisterAllocator::new(),
1164 }
1165 }
1166
1167 pub fn emit(&mut self, op: VdbeOp) -> usize {
1171 let addr = self.ops.len();
1172 self.ops.push(op);
1173 addr
1174 }
1175
1176 pub fn emit_op(&mut self, opcode: Opcode, p1: i32, p2: i32, p3: i32, p4: P4, p5: u16) -> usize {
1178 self.emit(VdbeOp {
1179 opcode,
1180 p1,
1181 p2,
1182 p3,
1183 p4,
1184 p5,
1185 })
1186 }
1187
1188 #[must_use]
1190 pub fn current_addr(&self) -> usize {
1191 self.ops.len()
1192 }
1193
1194 #[must_use]
1196 pub fn op_at(&self, addr: usize) -> Option<&VdbeOp> {
1197 self.ops.get(addr)
1198 }
1199
1200 #[must_use]
1202 pub fn op_at_mut(&mut self, addr: usize) -> Option<&mut VdbeOp> {
1203 self.ops.get_mut(addr)
1204 }
1205
1206 #[must_use]
1210 pub fn emit_label(&mut self) -> Label {
1211 let id = u32::try_from(self.labels.len()).expect("too many labels");
1212 self.labels.push(LabelState::Unresolved(Vec::new()));
1213 Label(id)
1214 }
1215
1216 pub fn emit_jump_to_label(
1220 &mut self,
1221 opcode: Opcode,
1222 p1: i32,
1223 p3: i32,
1224 label: Label,
1225 p4: P4,
1226 p5: u16,
1227 ) -> usize {
1228 let addr = self.emit(VdbeOp {
1229 opcode,
1230 p1,
1231 p2: -1, p3,
1233 p4,
1234 p5,
1235 });
1236
1237 let state = self
1238 .labels
1239 .get_mut(usize::try_from(label.0).expect("label fits usize"))
1240 .expect("label must exist");
1241
1242 match state {
1243 LabelState::Unresolved(refs) => refs.push(addr),
1244 LabelState::Resolved(target) => {
1245 self.ops[addr].p2 = *target;
1247 }
1248 }
1249
1250 addr
1251 }
1252
1253 pub fn resolve_label(&mut self, label: Label) {
1255 let addr = i32::try_from(self.current_addr()).expect("program too large");
1256 self.resolve_label_to(label, addr);
1257 }
1258
1259 pub fn resolve_label_to(&mut self, label: Label, address: i32) {
1261 let idx = usize::try_from(label.0).expect("label fits usize");
1262 let state = self.labels.get_mut(idx).expect("label must exist");
1263
1264 match state {
1265 LabelState::Unresolved(refs) => {
1266 for &ref_addr in refs.iter() {
1268 self.ops[ref_addr].p2 = address;
1269 }
1270 *state = LabelState::Resolved(address);
1271 }
1272 LabelState::Resolved(_) => {
1273 *state = LabelState::Resolved(address);
1275 }
1276 }
1277 }
1278
1279 pub fn alloc_reg(&mut self) -> i32 {
1283 self.regs.alloc_reg()
1284 }
1285
1286 pub fn alloc_regs(&mut self, n: i32) -> i32 {
1288 self.regs.alloc_regs(n)
1289 }
1290
1291 pub fn alloc_temp(&mut self) -> i32 {
1293 self.regs.alloc_temp()
1294 }
1295
1296 pub fn free_temp(&mut self, reg: i32) {
1298 self.regs.free_temp(reg);
1299 }
1300
1301 #[must_use]
1303 pub fn register_count(&self) -> i32 {
1304 self.regs.count()
1305 }
1306
1307 pub fn finish(self) -> Result<VdbeProgram> {
1311 for (i, state) in self.labels.iter().enumerate() {
1313 if let LabelState::Unresolved(refs) = state {
1314 if !refs.is_empty() {
1315 return Err(FrankenError::Internal(format!(
1316 "unresolved label {i} referenced by {} instruction(s)",
1317 refs.len()
1318 )));
1319 }
1320 }
1321 }
1322
1323 Ok(VdbeProgram {
1324 ops: self.ops,
1325 register_count: self.regs.count(),
1326 })
1327 }
1328}
1329
1330impl Default for ProgramBuilder {
1331 fn default() -> Self {
1332 Self::new()
1333 }
1334}
1335
1336#[derive(Debug, Clone, PartialEq)]
1338pub struct VdbeProgram {
1339 ops: SmallVec<[VdbeOp; 64]>,
1341 register_count: i32,
1343}
1344
1345impl VdbeProgram {
1346 #[must_use]
1348 pub fn ops(&self) -> &[VdbeOp] {
1349 &self.ops
1350 }
1351
1352 #[must_use]
1354 pub fn len(&self) -> usize {
1355 self.ops.len()
1356 }
1357
1358 #[must_use]
1360 pub fn is_empty(&self) -> bool {
1361 self.ops.is_empty()
1362 }
1363
1364 #[must_use]
1366 pub fn register_count(&self) -> i32 {
1367 self.register_count
1368 }
1369
1370 #[must_use]
1372 pub fn get(&self, pc: usize) -> Option<&VdbeOp> {
1373 self.ops.get(pc)
1374 }
1375
1376 #[must_use]
1380 pub fn disassemble(&self) -> String {
1381 use std::fmt::Write;
1382
1383 let mut out = std::string::String::with_capacity(self.ops.len() * 60);
1384 out.push_str("addr opcode p1 p2 p3 p4 p5\n");
1385 out.push_str("---- --------------- ---- ---- ---- ----------------- --\n");
1386
1387 for (addr, op) in self.ops.iter().enumerate() {
1388 let p4_str = match &op.p4 {
1389 P4::None => String::new(),
1390 P4::Int(v) => format!("(int){v}"),
1391 P4::Int64(v) => format!("(i64){v}"),
1392 P4::Real(v) => format!("(real){v}"),
1393 P4::Str(s) => format!("(str){s}"),
1394 P4::Blob(b) => format!("(blob)[{}B]", b.len()),
1395 P4::Collation(c) => format!("(coll){c}"),
1396 P4::FuncName(f) => format!("(func){f}"),
1397 P4::FuncNameCollated(f, c) => format!("(func){f} coll={c}"),
1398 P4::Table(t) => format!("(tbl){t}"),
1399 P4::Index(i) => format!("(idx){i}"),
1400 P4::Affinity(a) => format!("(aff){a}"),
1401 P4::TimeTravelCommitSeq(seq) => format!("(tt-seq){seq}"),
1402 P4::TimeTravelTimestamp(ts) => format!("(tt-ts){ts}"),
1403 };
1404
1405 writeln!(
1406 &mut out,
1407 "{addr:<4} {:<15} {:<4} {:<4} {:<4} {:<17} {:<2}",
1408 op.opcode.name(),
1409 op.p1,
1410 op.p2,
1411 op.p3,
1412 p4_str,
1413 op.p5,
1414 )
1415 .expect("write to string");
1416 }
1417
1418 out
1419 }
1420}
1421
1422#[cfg(test)]
1423#[allow(clippy::approx_constant)]
1424mod tests {
1425 use super::*;
1426 use std::collections::HashSet;
1427
1428 #[test]
1429 fn opcode_count() {
1430 assert_eq!(Opcode::COUNT, 192);
1431 }
1432
1433 #[test]
1434 fn opcode_name_roundtrip() {
1435 assert_eq!(Opcode::Goto.name(), "Goto");
1437 assert_eq!(Opcode::Halt.name(), "Halt");
1438 assert_eq!(Opcode::Insert.name(), "Insert");
1439 assert_eq!(Opcode::Delete.name(), "Delete");
1440 assert_eq!(Opcode::ResultRow.name(), "ResultRow");
1441 assert_eq!(Opcode::Noop.name(), "Noop");
1442 }
1443
1444 #[test]
1445 fn opcode_from_byte() {
1446 assert_eq!(Opcode::from_byte(0), None);
1447 assert_eq!(Opcode::from_byte(1), Some(Opcode::Goto));
1448 assert_eq!(Opcode::from_byte(8), Some(Opcode::Halt));
1449 assert_eq!(Opcode::from_byte(190), Some(Opcode::SetSnapshot));
1450 assert_eq!(Opcode::from_byte(191), Some(Opcode::Noop));
1451 assert_eq!(Opcode::from_byte(192), None);
1452 assert_eq!(Opcode::from_byte(255), None);
1453 }
1454
1455 #[test]
1456 fn opcode_from_byte_exhaustive() {
1457 for i in 1..=191u8 {
1459 assert!(
1460 Opcode::from_byte(i).is_some(),
1461 "from_byte({i}) returned None"
1462 );
1463 }
1464 }
1465
1466 #[test]
1467 fn test_opcode_distinct_u8_values() {
1468 let mut encoded = HashSet::new();
1469 for byte in 1..=191_u8 {
1470 let opcode = Opcode::from_byte(byte).expect("opcode byte must decode");
1471 let inserted = encoded.insert(opcode as u8);
1472 assert!(inserted, "duplicate opcode byte value for {:?}", opcode);
1473 }
1474
1475 assert_eq!(encoded.len(), 191, "every opcode must map to a unique byte");
1476 }
1477
1478 #[test]
1479 fn opcode_display() {
1480 assert_eq!(Opcode::Goto.to_string(), "Goto");
1481 assert_eq!(Opcode::Init.to_string(), "Init");
1482 }
1483
1484 #[test]
1485 fn opcode_is_jump() {
1486 assert!(Opcode::Goto.is_jump());
1487 assert!(Opcode::If.is_jump());
1488 assert!(Opcode::IfNot.is_jump());
1489 assert!(Opcode::Eq.is_jump());
1490 assert!(Opcode::Next.is_jump());
1491 assert!(Opcode::Rewind.is_jump());
1492 assert!(Opcode::Init.is_jump());
1493
1494 assert!(!Opcode::Integer.is_jump());
1495 assert!(!Opcode::Add.is_jump());
1496 assert!(!Opcode::Insert.is_jump());
1497 assert!(!Opcode::Noop.is_jump());
1498 assert!(!Opcode::ResultRow.is_jump());
1499 }
1500
1501 #[test]
1502 fn vdbe_op_basic() {
1503 let op = VdbeOp {
1504 opcode: Opcode::Integer,
1505 p1: 42,
1506 p2: 1,
1507 p3: 0,
1508 p4: P4::None,
1509 p5: 0,
1510 };
1511 assert_eq!(op.opcode, Opcode::Integer);
1512 assert_eq!(op.p1, 42);
1513 }
1514
1515 #[test]
1516 fn p4_variants() {
1517 let p4 = P4::Int(42);
1518 assert_eq!(p4, P4::Int(42));
1519
1520 let p4 = P4::Str("hello".to_owned());
1521 assert_eq!(p4, P4::Str("hello".to_owned()));
1522
1523 let p4 = P4::Real(3.14);
1524 assert_eq!(p4, P4::Real(3.14));
1525 }
1526}