New upstream version 3.0.5.33083.ds4
Damyan Ivanov
5 years ago
5 | 5 | <ItemDefinitionGroup> |
6 | 6 | <ClCompile> |
7 | 7 | <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> |
8 | <AdditionalOptions>/Zo %(AdditionalOptions)</AdditionalOptions> | |
8 | 9 | </ClCompile> |
9 | 10 | </ItemDefinitionGroup> |
10 | 11 | </Project>⏎ |
5 | 5 | <ItemDefinitionGroup> |
6 | 6 | <ClCompile> |
7 | 7 | <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> |
8 | <AdditionalOptions>/Zo %(AdditionalOptions)</AdditionalOptions> | |
8 | 9 | </ClCompile> |
9 | 10 | </ItemDefinitionGroup> |
10 | 11 | </Project>⏎ |
31 | 31 | #endif |
32 | 32 | #ifdef HAVE_SYS_TIMEB_H |
33 | 33 | #include <sys/timeb.h> |
34 | #endif | |
35 | ||
36 | #ifdef WIN_NT | |
37 | #include <windows.h> | |
34 | 38 | #endif |
35 | 39 | |
36 | 40 | #include "../common/classes/NoThrowTimeStamp.h" |
52 | 56 | // is going to to be somewhere in range between 1 ms (like on UNIX/Risc) |
53 | 57 | // and 53 ms (such as Win9X) |
54 | 58 | |
59 | int milliseconds; | |
60 | ||
61 | #ifdef WIN_NT | |
62 | FILETIME ftUtc, ftLocal; | |
63 | SYSTEMTIME stLocal; | |
64 | ||
65 | GetSystemTimeAsFileTime(&ftUtc); | |
66 | if (!FileTimeToLocalFileTime(&ftUtc, &ftLocal)) | |
67 | { | |
68 | if (error) | |
69 | *error = "FileTimeToLocalFileTime"; | |
70 | return result; | |
71 | } | |
72 | if (!FileTimeToSystemTime(&ftLocal, &stLocal)) | |
73 | { | |
74 | if (error) | |
75 | *error = "FileTimeToSystemTime"; | |
76 | return result; | |
77 | } | |
78 | ||
79 | milliseconds = stLocal.wMilliseconds; | |
80 | #else | |
55 | 81 | time_t seconds; // UTC time |
56 | int milliseconds; | |
57 | 82 | |
58 | 83 | #ifdef HAVE_GETTIMEOFDAY |
59 | 84 | struct timeval tp; |
66 | 91 | seconds = time_buffer.time; |
67 | 92 | milliseconds = time_buffer.millitm; |
68 | 93 | #endif |
94 | #endif // WIN_NT | |
69 | 95 | |
70 | 96 | // NS: Current FB behavior of using server time zone is not appropriate for |
71 | 97 | // distributed applications. We should be storing UTC times everywhere and |
77 | 103 | |
78 | 104 | const int fractions = milliseconds * ISC_TIME_SECONDS_PRECISION / 1000; |
79 | 105 | |
106 | #ifdef WIN_NT | |
107 | // Manually convert SYSTEMTIME to "struct tm" used below | |
108 | ||
109 | struct tm times, *ptimes = × | |
110 | ||
111 | times.tm_sec = stLocal.wSecond; // seconds after the minute - [0,59] | |
112 | times.tm_min = stLocal.wMinute; // minutes after the hour - [0,59] | |
113 | times.tm_hour = stLocal.wHour; // hours since midnight - [0,23] | |
114 | times.tm_mday = stLocal.wDay; // day of the month - [1,31] | |
115 | times.tm_mon = stLocal.wMonth - 1; // months since January - [0,11] | |
116 | times.tm_year = stLocal.wYear - 1900; // years since 1900 | |
117 | times.tm_wday = stLocal.wDayOfWeek; // days since Sunday - [0,6] | |
118 | ||
119 | // --- no used for encoding below | |
120 | times.tm_yday = 0; // days since January 1 - [0,365] | |
121 | times.tm_isdst = -1; // daylight savings time flag | |
122 | #else | |
80 | 123 | #ifdef HAVE_LOCALTIME_R |
81 | struct tm times; | |
124 | struct tm times, *ptimes = × | |
82 | 125 | if (!localtime_r(&seconds, ×)) |
83 | 126 | { |
84 | 127 | if (error) |
85 | 128 | *error = "localtime_r"; |
86 | 129 | return result; |
87 | 130 | } |
88 | ||
89 | result.encode(×, fractions); | |
90 | 131 | #else |
91 | struct tm *times = localtime(&seconds); | |
92 | if (!times) | |
132 | struct tm *ptimes = localtime(&seconds); | |
133 | if (!ptimes) | |
93 | 134 | { |
94 | 135 | if (error) |
95 | 136 | *error = "localtime"; |
96 | 137 | return result; |
97 | 138 | } |
98 | ||
99 | result.encode(times, fractions); | |
100 | #endif | |
101 | ||
139 | #endif | |
140 | #endif // WIN_NT | |
141 | ||
142 | result.encode(ptimes, fractions); | |
102 | 143 | return result; |
103 | 144 | } |
104 | 145 |
716 | 716 | } |
717 | 717 | |
718 | 718 | bool ListAggNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
719 | const dsc* desc, bool forceVarChar) | |
720 | { | |
721 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, forceVarChar) | | |
722 | PASS1_set_parameter_type(dsqlScratch, delimiter, desc, forceVarChar); | |
719 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
720 | { | |
721 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, node, forceVarChar) | | |
722 | PASS1_set_parameter_type(dsqlScratch, delimiter, desc, node, forceVarChar); | |
723 | 723 | } |
724 | 724 | |
725 | 725 | void ListAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) |
830 | 830 | dsc desc; |
831 | 831 | desc.makeText(charSet->maxBytesPerChar(), argDesc.getCharSet()); |
832 | 832 | |
833 | node->setParameterType(dsqlScratch, &desc, false); | |
833 | node->setParameterType(dsqlScratch, &desc, NULL, false); | |
834 | 834 | |
835 | 835 | return node; |
836 | 836 | } |
64 | 64 | virtual Firebird::string internalPrint(NodePrinter& printer) const; |
65 | 65 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
66 | 66 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
67 | const dsc* desc, bool forceVarChar); | |
67 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
68 | 68 | virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc); |
69 | 69 | virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const; |
70 | 70 |
439 | 439 | case blr_between: |
440 | 440 | { |
441 | 441 | // Try to force arg1 to be same type as arg2 eg: ? = FIELD case |
442 | PASS1_set_parameter_type(dsqlScratch, node->arg1, procArg2, false); | |
442 | PASS1_set_parameter_type(dsqlScratch, node->arg1, NULL, procArg2, false); | |
443 | 443 | |
444 | 444 | // Try to force arg2 to be same type as arg1 eg: FIELD = ? case |
445 | 445 | // Try even when the above call succeeded, because "arg2" may |
446 | 446 | // have arg-expressions that should be resolved. |
447 | PASS1_set_parameter_type(dsqlScratch, procArg2, node->arg1, false); | |
447 | PASS1_set_parameter_type(dsqlScratch, procArg2, NULL, node->arg1, false); | |
448 | 448 | |
449 | 449 | // X BETWEEN Y AND ? case |
450 | if (!PASS1_set_parameter_type(dsqlScratch, node->arg3, node->arg1, false)) | |
450 | if (!PASS1_set_parameter_type(dsqlScratch, node->arg3, NULL, node->arg1, false)) | |
451 | 451 | { |
452 | 452 | // ? BETWEEN Y AND ? case |
453 | PASS1_set_parameter_type(dsqlScratch, node->arg3, procArg2, false); | |
453 | PASS1_set_parameter_type(dsqlScratch, node->arg3, NULL, procArg2, false); | |
454 | 454 | } |
455 | 455 | |
456 | 456 | break; |
461 | 461 | case blr_similar: |
462 | 462 | case blr_starting: |
463 | 463 | // Try to force arg1 to be same type as arg2 eg: ? LIKE FIELD case |
464 | PASS1_set_parameter_type(dsqlScratch, node->arg1, procArg2, true); | |
464 | PASS1_set_parameter_type(dsqlScratch, node->arg1, NULL, procArg2, true); | |
465 | 465 | |
466 | 466 | // Try to force arg2 same type as arg 1 eg: FIELD LIKE ? case |
467 | 467 | // Try even when the above call succeeded, because "arg2" may |
468 | 468 | // have arg-expressions that should be resolved. |
469 | PASS1_set_parameter_type(dsqlScratch, procArg2, node->arg1, true); | |
469 | PASS1_set_parameter_type(dsqlScratch, procArg2, NULL, node->arg1, true); | |
470 | 470 | |
471 | 471 | // X LIKE Y ESCAPE ? case |
472 | PASS1_set_parameter_type(dsqlScratch, node->arg3, procArg2, true); | |
472 | PASS1_set_parameter_type(dsqlScratch, node->arg3, NULL, procArg2, true); | |
473 | 473 | } |
474 | 474 | |
475 | 475 | return node; |
1287 | 1287 | ComparativeBoolNode* cmpNode = FB_NEW_POOL(getPool()) ComparativeBoolNode(getPool(), blrOp, |
1288 | 1288 | doDsqlPass(dsqlScratch, arg1, false), rse->dsqlSelectList->items[0]); |
1289 | 1289 | |
1290 | PASS1_set_parameter_type(dsqlScratch, cmpNode->arg1, cmpNode->arg2, false); | |
1290 | PASS1_set_parameter_type(dsqlScratch, cmpNode->arg1, NULL, cmpNode->arg2, false); | |
1291 | 1291 | |
1292 | 1292 | rse->dsqlWhere = cmpNode; |
1293 | 1293 | |
1338 | 1338 | MissingBoolNode* node = FB_NEW_POOL(getPool()) MissingBoolNode(getPool(), |
1339 | 1339 | doDsqlPass(dsqlScratch, arg)); |
1340 | 1340 | |
1341 | PASS1_set_parameter_type(dsqlScratch, node->arg, (dsc*) NULL, false); | |
1341 | PASS1_set_parameter_type(dsqlScratch, node->arg, NULL, NULL, false); | |
1342 | 1342 | |
1343 | 1343 | dsc desc; |
1344 | 1344 | MAKE_desc(dsqlScratch, &desc, node->arg); |
448 | 448 | } |
449 | 449 | |
450 | 450 | bool ArithmeticNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
451 | const dsc* desc, bool forceVarChar) | |
452 | { | |
453 | return PASS1_set_parameter_type(dsqlScratch, arg1, desc, forceVarChar) | | |
454 | PASS1_set_parameter_type(dsqlScratch, arg2, desc, forceVarChar); | |
451 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
452 | { | |
453 | return PASS1_set_parameter_type(dsqlScratch, arg1, desc, node, forceVarChar) | | |
454 | PASS1_set_parameter_type(dsqlScratch, arg2, desc, node, forceVarChar); | |
455 | 455 | } |
456 | 456 | |
457 | 457 | void ArithmeticNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
2677 | 2677 | node->dsqlField = dsqlField; |
2678 | 2678 | |
2679 | 2679 | DDL_resolve_intl_type(dsqlScratch, node->dsqlField, NULL); |
2680 | node->setParameterType(dsqlScratch, NULL, false); | |
2680 | node->setParameterType(dsqlScratch, NULL, NULL, false); | |
2681 | 2681 | |
2682 | 2682 | MAKE_desc_from_field(&node->castDesc, node->dsqlField); |
2683 | 2683 | MAKE_desc(dsqlScratch, &node->source->nodDesc, node->source); |
2693 | 2693 | } |
2694 | 2694 | |
2695 | 2695 | bool CastNode::setParameterType(DsqlCompilerScratch* /*dsqlScratch*/, |
2696 | const dsc* /*desc*/, bool /*forceVarChar*/) | |
2696 | const dsc* /*desc*/, ValueExprNode* /*node*/, bool /*forceVarChar*/) | |
2697 | 2697 | { |
2698 | 2698 | // ASF: Attention: CastNode::dsqlPass calls us with NULL node. |
2699 | 2699 | |
2921 | 2921 | CoalesceNode* node = FB_NEW_POOL(getPool()) CoalesceNode(getPool(), |
2922 | 2922 | doDsqlPass(dsqlScratch, args)); |
2923 | 2923 | node->make(dsqlScratch, &node->nodDesc); // Set descriptor for output node. |
2924 | node->setParameterType(dsqlScratch, &node->nodDesc, false); | |
2924 | node->setParameterType(dsqlScratch, &node->nodDesc, NULL, false); | |
2925 | 2925 | return node; |
2926 | 2926 | } |
2927 | 2927 | |
2931 | 2931 | } |
2932 | 2932 | |
2933 | 2933 | bool CoalesceNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
2934 | const dsc* desc, bool /*forceVarChar*/) | |
2934 | const dsc* desc, ValueExprNode* node, bool /*forceVarChar*/) | |
2935 | 2935 | { |
2936 | 2936 | bool ret = false; |
2937 | 2937 | |
2938 | 2938 | for (NestConst<ValueExprNode>* ptr = args->items.begin(); ptr != args->items.end(); ++ptr) |
2939 | ret |= PASS1_set_parameter_type(dsqlScratch, *ptr, desc, false); | |
2939 | { | |
2940 | ret |= PASS1_set_parameter_type(dsqlScratch, *ptr, desc, node, false); | |
2941 | } | |
2940 | 2942 | |
2941 | 2943 | return ret; |
2942 | 2944 | } |
3137 | 3139 | } |
3138 | 3140 | |
3139 | 3141 | bool ConcatenateNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
3140 | const dsc* desc, bool forceVarChar) | |
3141 | { | |
3142 | return PASS1_set_parameter_type(dsqlScratch, arg1, desc, forceVarChar) | | |
3143 | PASS1_set_parameter_type(dsqlScratch, arg2, desc, forceVarChar); | |
3142 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
3143 | { | |
3144 | return PASS1_set_parameter_type(dsqlScratch, arg1, desc, node, forceVarChar) | | |
3145 | PASS1_set_parameter_type(dsqlScratch, arg2, desc, node, forceVarChar); | |
3144 | 3146 | } |
3145 | 3147 | |
3146 | 3148 | void ConcatenateNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
3914 | 3916 | doDsqlPass(dsqlScratch, conditions), doDsqlPass(dsqlScratch, values)); |
3915 | 3917 | node->label = label; |
3916 | 3918 | node->make(dsqlScratch, &node->nodDesc); // Set descriptor for output node. |
3917 | node->setParameterType(dsqlScratch, &node->nodDesc, false); | |
3919 | node->setParameterType(dsqlScratch, &node->nodDesc, NULL, false); | |
3918 | 3920 | |
3919 | 3921 | // Workaround for DECODE/CASE supporting only 255 items - see CORE-5366. |
3920 | 3922 | |
3977 | 3979 | } |
3978 | 3980 | |
3979 | 3981 | bool DecodeNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
3980 | const dsc* desc, bool /*forceVarChar*/) | |
3982 | const dsc* desc, ValueExprNode* node, bool /*forceVarChar*/) | |
3981 | 3983 | { |
3982 | 3984 | // Check if there is a parameter in the test/conditions. |
3983 | 3985 | bool setParameters = test->is<ParameterNode>(); |
4021 | 4023 | if (!node1Desc.isUnknown()) |
4022 | 4024 | { |
4023 | 4025 | // Set parameter describe information. |
4024 | PASS1_set_parameter_type(dsqlScratch, test, &node1Desc, false); | |
4026 | PASS1_set_parameter_type(dsqlScratch, test, &node1Desc, NULL, false); | |
4025 | 4027 | |
4026 | 4028 | for (NestConst<ValueExprNode>* ptr = conditions->items.begin(); |
4027 | 4029 | ptr != conditions->items.end(); |
4028 | 4030 | ++ptr) |
4029 | 4031 | { |
4030 | PASS1_set_parameter_type(dsqlScratch, *ptr, &node1Desc, false); | |
4032 | PASS1_set_parameter_type(dsqlScratch, *ptr, &node1Desc, NULL, false); | |
4031 | 4033 | } |
4032 | 4034 | } |
4033 | 4035 | } |
4035 | 4037 | bool ret = false; |
4036 | 4038 | |
4037 | 4039 | for (NestConst<ValueExprNode>* ptr = values->items.begin(); ptr != values->items.end(); ++ptr) |
4038 | ret |= PASS1_set_parameter_type(dsqlScratch, *ptr, desc, false); | |
4040 | { | |
4041 | ret |= PASS1_set_parameter_type(dsqlScratch, *ptr, desc, node, false); | |
4042 | } | |
4039 | 4043 | |
4040 | 4044 | return ret; |
4041 | 4045 | } |
4478 | 4482 | } |
4479 | 4483 | |
4480 | 4484 | bool ExtractNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
4481 | const dsc* desc, bool forceVarChar) | |
4482 | { | |
4483 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, forceVarChar); | |
4485 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
4486 | { | |
4487 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, node, forceVarChar); | |
4484 | 4488 | } |
4485 | 4489 | |
4486 | 4490 | void ExtractNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
5997 | 6001 | } |
5998 | 6002 | |
5999 | 6003 | bool GenIdNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
6000 | const dsc* desc, bool forceVarChar) | |
6001 | { | |
6002 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, forceVarChar); | |
6004 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
6005 | { | |
6006 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, node, forceVarChar); | |
6003 | 6007 | } |
6004 | 6008 | |
6005 | 6009 | void GenIdNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
6695 | 6699 | parameter->par_name = parameter->par_alias = "CONSTANT"; |
6696 | 6700 | } |
6697 | 6701 | |
6698 | bool LiteralNode::setParameterType(DsqlCompilerScratch* /*dsqlScratch*/, | |
6699 | const dsc* /*desc*/, bool /*forceVarChar*/) | |
6700 | { | |
6701 | return false; | |
6702 | } | |
6703 | ||
6704 | 6702 | void LiteralNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
6705 | 6703 | { |
6706 | 6704 | if (litDesc.dsc_dtype == dtype_text) |
7313 | 7311 | } |
7314 | 7312 | |
7315 | 7313 | bool NegateNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
7316 | const dsc* desc, bool forceVarChar) | |
7317 | { | |
7318 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, forceVarChar); | |
7314 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
7315 | { | |
7316 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, node, forceVarChar); | |
7319 | 7317 | } |
7320 | 7318 | |
7321 | 7319 | void NegateNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
7886 | 7884 | } |
7887 | 7885 | |
7888 | 7886 | bool ParameterNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
7889 | const dsc* desc, bool forceVarChar) | |
7887 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
7890 | 7888 | { |
7891 | 7889 | thread_db* tdbb = JRD_get_thread_data(); |
7892 | 7890 | |
7893 | 7891 | const dsc oldDesc = dsqlParameter->par_desc; |
7894 | 7892 | |
7895 | if (!desc) | |
7893 | if (!desc && !node) | |
7896 | 7894 | dsqlParameter->par_desc.makeNullString(); |
7897 | 7895 | else |
7898 | 7896 | { |
7897 | if (!desc) | |
7898 | { | |
7899 | MAKE_desc(dsqlScratch, &node->nodDesc, node); | |
7900 | desc = &node->nodDesc; | |
7901 | } | |
7902 | ||
7899 | 7903 | dsqlParameter->par_desc = *desc; |
7900 | 7904 | |
7901 | 7905 | if (tdbb->getCharSet() != CS_NONE && tdbb->getCharSet() != CS_BINARY) |
8951 | 8955 | } |
8952 | 8956 | |
8953 | 8957 | bool StrCaseNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
8954 | const dsc* desc, bool forceVarChar) | |
8955 | { | |
8956 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, forceVarChar); | |
8958 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
8959 | { | |
8960 | return PASS1_set_parameter_type(dsqlScratch, arg, desc, node, forceVarChar); | |
8957 | 8961 | } |
8958 | 8962 | |
8959 | 8963 | void StrCaseNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
9167 | 9171 | } |
9168 | 9172 | |
9169 | 9173 | parameter->par_name = parameter->par_alias = alias; |
9170 | } | |
9171 | ||
9172 | bool StrLenNode::setParameterType(DsqlCompilerScratch* dsqlScratch, | |
9173 | const dsc* desc, bool forceVarChar) | |
9174 | { | |
9175 | return false; | |
9176 | 9174 | } |
9177 | 9175 | |
9178 | 9176 | void StrLenNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
9893 | 9891 | } |
9894 | 9892 | |
9895 | 9893 | bool SubstringNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
9896 | const dsc* desc, bool forceVarChar) | |
9897 | { | |
9898 | return PASS1_set_parameter_type(dsqlScratch, expr, desc, forceVarChar) | | |
9899 | PASS1_set_parameter_type(dsqlScratch, start, desc, forceVarChar) | | |
9900 | PASS1_set_parameter_type(dsqlScratch, length, desc, forceVarChar); | |
9894 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
9895 | { | |
9896 | return PASS1_set_parameter_type(dsqlScratch, expr, desc, node, forceVarChar) | | |
9897 | PASS1_set_parameter_type(dsqlScratch, start, desc, node, forceVarChar) | | |
9898 | PASS1_set_parameter_type(dsqlScratch, length, desc, node, forceVarChar); | |
9901 | 9899 | } |
9902 | 9900 | |
9903 | 9901 | void SubstringNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
10227 | 10225 | } |
10228 | 10226 | |
10229 | 10227 | bool SubstringSimilarNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
10230 | const dsc* desc, bool forceVarChar) | |
10231 | { | |
10232 | return PASS1_set_parameter_type(dsqlScratch, expr, desc, forceVarChar) | | |
10233 | PASS1_set_parameter_type(dsqlScratch, pattern, desc, forceVarChar) | | |
10234 | PASS1_set_parameter_type(dsqlScratch, escape, desc, forceVarChar); | |
10228 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
10229 | { | |
10230 | return PASS1_set_parameter_type(dsqlScratch, expr, desc, node, forceVarChar) | | |
10231 | PASS1_set_parameter_type(dsqlScratch, pattern, desc, node, forceVarChar) | | |
10232 | PASS1_set_parameter_type(dsqlScratch, escape, desc, node, forceVarChar); | |
10235 | 10233 | } |
10236 | 10234 | |
10237 | 10235 | void SubstringSimilarNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
10411 | 10409 | doDsqlPass(dsqlScratch, escape)); |
10412 | 10410 | |
10413 | 10411 | // ? SIMILAR FIELD case. |
10414 | PASS1_set_parameter_type(dsqlScratch, node->expr, node->pattern, true); | |
10412 | PASS1_set_parameter_type(dsqlScratch, node->expr, NULL, node->pattern, true); | |
10415 | 10413 | |
10416 | 10414 | // FIELD SIMILAR ? case. |
10417 | PASS1_set_parameter_type(dsqlScratch, node->pattern, node->expr, true); | |
10415 | PASS1_set_parameter_type(dsqlScratch, node->pattern, NULL, node->expr, true); | |
10418 | 10416 | |
10419 | 10417 | // X SIMILAR Y ESCAPE ? case. |
10420 | PASS1_set_parameter_type(dsqlScratch, node->escape, node->pattern, true); | |
10418 | PASS1_set_parameter_type(dsqlScratch, node->escape, NULL, node->pattern, true); | |
10421 | 10419 | |
10422 | 10420 | return node; |
10423 | 10421 | } |
10613 | 10611 | for (unsigned int i = 0; i < inList->items.getCount(); ++i) |
10614 | 10612 | { |
10615 | 10613 | ValueExprNode* p = inList->items[i]; |
10616 | PASS1_set_parameter_type(dsqlScratch, p, &p->nodDesc, false); | |
10614 | PASS1_set_parameter_type(dsqlScratch, p, &p->nodDesc, NULL, false); | |
10617 | 10615 | } |
10618 | 10616 | } |
10619 | 10617 | |
10668 | 10666 | doDsqlPass(dsqlScratch, value), doDsqlPass(dsqlScratch, trimChars)); |
10669 | 10667 | |
10670 | 10668 | // Try to force trimChars to be same type as value: TRIM(? FROM FIELD) |
10671 | PASS1_set_parameter_type(dsqlScratch, node->trimChars, node->value, false); | |
10669 | PASS1_set_parameter_type(dsqlScratch, node->trimChars, NULL, node->value, false); | |
10672 | 10670 | |
10673 | 10671 | return node; |
10674 | 10672 | } |
10679 | 10677 | } |
10680 | 10678 | |
10681 | 10679 | bool TrimNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
10682 | const dsc* desc, bool forceVarChar) | |
10683 | { | |
10684 | return PASS1_set_parameter_type(dsqlScratch, value, desc, forceVarChar) | | |
10685 | PASS1_set_parameter_type(dsqlScratch, trimChars, desc, forceVarChar); | |
10680 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
10681 | { | |
10682 | return PASS1_set_parameter_type(dsqlScratch, value, desc, node, forceVarChar) | | |
10683 | PASS1_set_parameter_type(dsqlScratch, trimChars, desc, node, forceVarChar); | |
10686 | 10684 | } |
10687 | 10685 | |
10688 | 10686 | void TrimNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
11470 | 11468 | } |
11471 | 11469 | |
11472 | 11470 | if (pos < node->dsqlFunction->udf_arguments.getCount()) |
11473 | PASS1_set_parameter_type(dsqlScratch, *ptr, &desc, false); | |
11471 | PASS1_set_parameter_type(dsqlScratch, *ptr, &desc, NULL, false); | |
11474 | 11472 | else |
11475 | 11473 | { |
11476 | 11474 | // We should complain here in the future! The parameter is |
11664 | 11662 | doDsqlPass(dsqlScratch, trueValue), |
11665 | 11663 | doDsqlPass(dsqlScratch, falseValue)); |
11666 | 11664 | |
11667 | PASS1_set_parameter_type(dsqlScratch, node->trueValue, node->falseValue, false); | |
11668 | PASS1_set_parameter_type(dsqlScratch, node->falseValue, node->trueValue, false); | |
11665 | PASS1_set_parameter_type(dsqlScratch, node->trueValue, NULL, node->falseValue, false); | |
11666 | PASS1_set_parameter_type(dsqlScratch, node->falseValue, NULL, node->trueValue, false); | |
11669 | 11667 | |
11670 | 11668 | return node; |
11671 | 11669 | } |
11676 | 11674 | } |
11677 | 11675 | |
11678 | 11676 | bool ValueIfNode::setParameterType(DsqlCompilerScratch* dsqlScratch, |
11679 | const dsc* desc, bool forceVarChar) | |
11680 | { | |
11681 | return PASS1_set_parameter_type(dsqlScratch, trueValue, desc, forceVarChar) | | |
11682 | PASS1_set_parameter_type(dsqlScratch, falseValue, desc, forceVarChar); | |
11677 | const dsc* desc, ValueExprNode* node, bool forceVarChar) | |
11678 | { | |
11679 | return PASS1_set_parameter_type(dsqlScratch, trueValue, desc, node, forceVarChar) | | |
11680 | PASS1_set_parameter_type(dsqlScratch, falseValue, desc, node, forceVarChar); | |
11683 | 11681 | } |
11684 | 11682 | |
11685 | 11683 | void ValueIfNode::genBlr(DsqlCompilerScratch* dsqlScratch) |
50 | 50 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
51 | 51 | virtual void setParameterName(dsql_par* parameter) const; |
52 | 52 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
53 | const dsc* desc, bool forceVarChar); | |
53 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
54 | 54 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
55 | 55 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
56 | 56 | |
175 | 175 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
176 | 176 | virtual void setParameterName(dsql_par* parameter) const; |
177 | 177 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
178 | const dsc* desc, bool forceVarChar); | |
178 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
179 | 179 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
180 | 180 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
181 | 181 | |
213 | 213 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
214 | 214 | virtual void setParameterName(dsql_par* parameter) const; |
215 | 215 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
216 | const dsc* desc, bool forceVarChar); | |
216 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
217 | 217 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
218 | 218 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
219 | 219 | |
297 | 297 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
298 | 298 | virtual void setParameterName(dsql_par* parameter) const; |
299 | 299 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
300 | const dsc* desc, bool forceVarChar); | |
300 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
301 | 301 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
302 | 302 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
303 | 303 | |
462 | 462 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
463 | 463 | virtual void setParameterName(dsql_par* parameter) const; |
464 | 464 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
465 | const dsc* desc, bool forceVarChar); | |
465 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
466 | 466 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
467 | 467 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
468 | 468 | |
581 | 581 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
582 | 582 | virtual void setParameterName(dsql_par* parameter) const; |
583 | 583 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
584 | const dsc* desc, bool forceVarChar); | |
584 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
585 | 585 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
586 | 586 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
587 | 587 | |
685 | 685 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
686 | 686 | virtual void setParameterName(dsql_par* parameter) const; |
687 | 687 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
688 | const dsc* desc, bool forceVarChar); | |
688 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
689 | 689 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
690 | 690 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
691 | 691 | |
752 | 752 | virtual Firebird::string internalPrint(NodePrinter& printer) const; |
753 | 753 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
754 | 754 | virtual void setParameterName(dsql_par* parameter) const; |
755 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, | |
756 | const dsc* desc, bool forceVarChar); | |
757 | 755 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
758 | 756 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
759 | 757 | |
918 | 916 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
919 | 917 | virtual void setParameterName(dsql_par* parameter) const; |
920 | 918 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
921 | const dsc* desc, bool forceVarChar); | |
919 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
922 | 920 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
923 | 921 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
924 | 922 | |
1061 | 1059 | } |
1062 | 1060 | |
1063 | 1061 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
1064 | const dsc* desc, bool forceVarChar); | |
1062 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
1065 | 1063 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
1066 | 1064 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
1067 | 1065 | virtual bool dsqlMatch(const ExprNode* other, bool ignoreMapCast) const; |
1268 | 1266 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
1269 | 1267 | virtual void setParameterName(dsql_par* parameter) const; |
1270 | 1268 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
1271 | const dsc* desc, bool forceVarChar); | |
1269 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
1272 | 1270 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
1273 | 1271 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
1274 | 1272 | |
1295 | 1293 | virtual Firebird::string internalPrint(NodePrinter& printer) const; |
1296 | 1294 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
1297 | 1295 | virtual void setParameterName(dsql_par* parameter) const; |
1298 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, | |
1299 | const dsc* desc, bool forceVarChar); | |
1300 | 1296 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
1301 | 1297 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
1302 | 1298 | |
1382 | 1378 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
1383 | 1379 | virtual void setParameterName(dsql_par* parameter) const; |
1384 | 1380 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
1385 | const dsc* desc, bool forceVarChar); | |
1381 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
1386 | 1382 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
1387 | 1383 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
1388 | 1384 | |
1413 | 1409 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
1414 | 1410 | virtual void setParameterName(dsql_par* parameter) const; |
1415 | 1411 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
1416 | const dsc* desc, bool forceVarChar); | |
1412 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
1417 | 1413 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
1418 | 1414 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
1419 | 1415 | |
1471 | 1467 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
1472 | 1468 | virtual void setParameterName(dsql_par* parameter) const; |
1473 | 1469 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
1474 | const dsc* desc, bool forceVarChar); | |
1470 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
1475 | 1471 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
1476 | 1472 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
1477 | 1473 | |
1546 | 1542 | virtual ValueExprNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); |
1547 | 1543 | virtual void setParameterName(dsql_par* parameter) const; |
1548 | 1544 | virtual bool setParameterType(DsqlCompilerScratch* dsqlScratch, |
1549 | const dsc* desc, bool forceVarChar); | |
1545 | const dsc* desc, ValueExprNode* node, bool forceVarChar); | |
1550 | 1546 | virtual void genBlr(DsqlCompilerScratch* dsqlScratch); |
1551 | 1547 | virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); |
1552 | 1548 |
782 | 782 | } |
783 | 783 | |
784 | 784 | virtual bool setParameterType(DsqlCompilerScratch* /*dsqlScratch*/, |
785 | const dsc* /*desc*/, bool /*forceVarChar*/) | |
785 | const dsc* /*desc*/, ValueExprNode* /*node*/, bool /*forceVarChar*/) | |
786 | 786 | { |
787 | 787 | return false; |
788 | 788 | } |
322 | 322 | dsqlValidateTarget(node->asgnTo); |
323 | 323 | |
324 | 324 | // Try to force asgnFrom to be same type as asgnTo eg: ? = FIELD case |
325 | PASS1_set_parameter_type(dsqlScratch, node->asgnFrom, node->asgnTo, false); | |
325 | PASS1_set_parameter_type(dsqlScratch, node->asgnFrom, NULL, node->asgnTo, false); | |
326 | 326 | |
327 | 327 | // Try to force asgnTo to be same type as asgnFrom eg: FIELD = ? case |
328 | 328 | // Try even when the above call succeeded, because "asgnTo" may |
329 | 329 | // have sub-expressions that should be resolved. |
330 | PASS1_set_parameter_type(dsqlScratch, node->asgnTo, node->asgnFrom, false); | |
330 | PASS1_set_parameter_type(dsqlScratch, node->asgnTo, NULL, node->asgnFrom, false); | |
331 | 331 | |
332 | 332 | return node; |
333 | 333 | } |
2704 | 2704 | DEV_BLKCHK(field, dsql_type_fld); |
2705 | 2705 | DEV_BLKCHK(*ptr, dsql_type_nod); |
2706 | 2706 | MAKE_desc_from_field(&desc_node, field); |
2707 | PASS1_set_parameter_type(dsqlScratch, *ptr, &desc_node, false); | |
2707 | PASS1_set_parameter_type(dsqlScratch, *ptr, &desc_node, NULL, false); | |
2708 | 2708 | } |
2709 | 2709 | } |
2710 | 2710 | |
3950 | 3950 | |
3951 | 3951 | newParam->type->flags |= FLD_nullable; |
3952 | 3952 | MAKE_desc_from_field(&desc_node, newParam->type); |
3953 | PASS1_set_parameter_type(dsqlScratch, temp, &desc_node, false); | |
3953 | PASS1_set_parameter_type(dsqlScratch, temp, &desc_node, NULL, false); | |
3954 | 3954 | } // end scope |
3955 | 3955 | |
3956 | 3956 | if (param != parameters.begin()) |
5259 | 5259 | |
5260 | 5260 | for (FB_SIZE_T i = 0; i < assignStatements->statements.getCount(); ++i) |
5261 | 5261 | { |
5262 | if (!PASS1_set_parameter_type(dsqlScratch, orgValues[i], newValues[i], false)) | |
5263 | PASS1_set_parameter_type(dsqlScratch, newValues[i], orgValues[i], false); | |
5262 | if (!PASS1_set_parameter_type(dsqlScratch, orgValues[i], NULL, newValues[i], false)) | |
5263 | PASS1_set_parameter_type(dsqlScratch, newValues[i], NULL, orgValues[i], false); | |
5264 | 5264 | |
5265 | 5265 | AssignmentNode* assign = FB_NEW_POOL(pool) AssignmentNode(pool); |
5266 | 5266 | assign->asgnFrom = orgValues[i]; |
5796 | 5796 | ValueExprNode* const sub1 = orgValues[j]; |
5797 | 5797 | ValueExprNode* const sub2 = newValues[j]; |
5798 | 5798 | |
5799 | if (!PASS1_set_parameter_type(dsqlScratch, sub1, sub2, false)) | |
5800 | PASS1_set_parameter_type(dsqlScratch, sub2, sub1, false); | |
5799 | if (!PASS1_set_parameter_type(dsqlScratch, sub1, NULL, sub2, false)) | |
5800 | PASS1_set_parameter_type(dsqlScratch, sub2, NULL, sub1, false); | |
5801 | 5801 | |
5802 | 5802 | AssignmentNode* assign = FB_NEW_POOL(pool) AssignmentNode(pool); |
5803 | 5803 | assign->asgnFrom = sub1; |
6568 | 6568 | temp->asgnTo = *ptr; |
6569 | 6569 | assignStatements->statements.add(temp); |
6570 | 6570 | |
6571 | PASS1_set_parameter_type(dsqlScratch, *ptr2, temp->asgnTo, false); | |
6571 | PASS1_set_parameter_type(dsqlScratch, *ptr2, NULL, temp->asgnTo, false); | |
6572 | 6572 | } |
6573 | 6573 | } |
6574 | 6574 |
544 | 544 | { |
545 | 545 | DEV_BLKCHK(field, dsql_type_fld); |
546 | 546 | MAKE_desc_from_field(&desc_node, field); |
547 | PASS1_set_parameter_type(dsqlScratch, *input, &desc_node, false); | |
547 | PASS1_set_parameter_type(dsqlScratch, *input, &desc_node, NULL, false); | |
548 | 548 | } |
549 | 549 | } |
550 | 550 | } |
1509 | 1509 | descNode.makeInt64(0); |
1510 | 1510 | |
1511 | 1511 | rse->dsqlFirst = Node::doDsqlPass(dsqlScratch, firstNode, false); |
1512 | PASS1_set_parameter_type(dsqlScratch, rse->dsqlFirst, &descNode, false); | |
1512 | PASS1_set_parameter_type(dsqlScratch, rse->dsqlFirst, &descNode, NULL, false); | |
1513 | 1513 | |
1514 | 1514 | rse->dsqlSkip = Node::doDsqlPass(dsqlScratch, skipNode, false); |
1515 | PASS1_set_parameter_type(dsqlScratch, rse->dsqlSkip, &descNode, false); | |
1515 | PASS1_set_parameter_type(dsqlScratch, rse->dsqlSkip, &descNode, NULL, false); | |
1516 | 1516 | } |
1517 | 1517 | |
1518 | 1518 | |
2898 | 2898 | |
2899 | 2899 | // Setup the datatype of a parameter. |
2900 | 2900 | bool PASS1_set_parameter_type(DsqlCompilerScratch* dsqlScratch, ValueExprNode* inNode, |
2901 | const dsc* desc, bool force_varchar) | |
2902 | { | |
2903 | return inNode && inNode->setParameterType(dsqlScratch, desc, force_varchar); | |
2904 | } | |
2905 | ||
2906 | // Setup the datatype of a parameter. | |
2907 | bool PASS1_set_parameter_type(DsqlCompilerScratch* dsqlScratch, ValueExprNode* inNode, | |
2908 | ValueExprNode* node, bool force_varchar) | |
2909 | { | |
2910 | if (!inNode) | |
2911 | return false; | |
2912 | ||
2913 | MAKE_desc(dsqlScratch, &node->nodDesc, node); | |
2914 | return inNode->setParameterType(dsqlScratch, &node->nodDesc, force_varchar); | |
2901 | const dsc* desc, ValueExprNode* node, bool force_varchar) | |
2902 | { | |
2903 | return inNode && inNode->setParameterType(dsqlScratch, desc, node, force_varchar); | |
2915 | 2904 | } |
2916 | 2905 | |
2917 | 2906 |
53 | 53 | Jrd::ValueListNode*, Jrd::ValueListNode*); |
54 | 54 | Jrd::RecordSourceNode* PASS1_relation(Jrd::DsqlCompilerScratch*, Jrd::RecordSourceNode*); |
55 | 55 | Jrd::RseNode* PASS1_rse(Jrd::DsqlCompilerScratch*, Jrd::SelectExprNode*, bool); |
56 | bool PASS1_set_parameter_type(Jrd::DsqlCompilerScratch*, Jrd::ValueExprNode*, const dsc*, bool); | |
57 | bool PASS1_set_parameter_type(Jrd::DsqlCompilerScratch*, Jrd::ValueExprNode*, Jrd::ValueExprNode*, bool); | |
56 | bool PASS1_set_parameter_type(Jrd::DsqlCompilerScratch*, Jrd::ValueExprNode*, const dsc*, Jrd::ValueExprNode*, bool); | |
58 | 57 | Jrd::ValueListNode* PASS1_sort(Jrd::DsqlCompilerScratch*, Jrd::ValueListNode*, Jrd::ValueListNode*); |
59 | 58 | |
60 | 59 | #endif // DSQL_PASS1_PROTO_H |
509 | 509 | } |
510 | 510 | |
511 | 511 | if (sort) |
512 | analyzeNavigation(); | |
512 | analyzeNavigation(inversions); | |
513 | 513 | |
514 | 514 | #ifdef OPT_DEBUG_RETRIEVAL |
515 | 515 | // Debug |
608 | 608 | if (!navigationCandidate) |
609 | 609 | return NULL; |
610 | 610 | |
611 | IndexScratch* const scratch = navigationCandidate->scratch; | |
612 | ||
611 | 613 | // Looks like we can do a navigational walk. Flag that |
612 | 614 | // we have used this index for navigation, and allocate |
613 | 615 | // a navigational rsb for it. |
614 | navigationCandidate->idx->idx_runtime_flags |= idx_navigate; | |
616 | scratch->idx->idx_runtime_flags |= idx_navigate; | |
615 | 617 | |
616 | 618 | const USHORT key_length = |
617 | ROUNDUP(BTR_key_length(tdbb, relation, navigationCandidate->idx), sizeof(SLONG)); | |
618 | ||
619 | InversionNode* const index_node = makeIndexScanNode(navigationCandidate); | |
619 | ROUNDUP(BTR_key_length(tdbb, relation, scratch->idx), sizeof(SLONG)); | |
620 | ||
621 | InversionNode* const index_node = makeIndexScanNode(scratch); | |
620 | 622 | |
621 | 623 | return FB_NEW_POOL(*tdbb->getDefaultPool()) |
622 | 624 | IndexTableScan(csb, getAlias(), stream, relation, index_node, key_length); |
623 | 625 | } |
624 | 626 | |
625 | void OptimizerRetrieval::analyzeNavigation() | |
627 | void OptimizerRetrieval::analyzeNavigation(const InversionCandidateList& inversions) | |
626 | 628 | { |
627 | 629 | /************************************** |
628 | 630 | * |
799 | 801 | if (!usableIndex) |
800 | 802 | continue; |
801 | 803 | |
804 | // Lookup the inversion candidate matching our navigational index | |
805 | ||
806 | InversionCandidate* candidate = NULL; | |
807 | ||
808 | for (InversionCandidate* const* iter = inversions.begin(); | |
809 | iter != inversions.end(); ++iter) | |
810 | { | |
811 | if ((*iter)->scratch == indexScratch) | |
812 | { | |
813 | candidate = *iter; | |
814 | break; | |
815 | } | |
816 | } | |
817 | ||
818 | if (candidate && !optimizer->optimizeFirstRows) | |
819 | { | |
820 | // Check whether the navigational index has any matches shared with other inversion | |
821 | // candidates. If so, compare inversions and decide whether navigation is acceptable. | |
822 | ||
823 | for (const InversionCandidate* const* iter = inversions.begin(); | |
824 | iter != inversions.end(); ++iter) | |
825 | { | |
826 | const InversionCandidate* const otherCandidate = *iter; | |
827 | ||
828 | if (otherCandidate != candidate) | |
829 | { | |
830 | for (BoolExprNode* const* iter2 = otherCandidate->matches.begin(); | |
831 | iter2 != otherCandidate->matches.end(); ++iter2) | |
832 | { | |
833 | if (candidate->matches.exist(*iter2)) | |
834 | { | |
835 | usableIndex = betterInversion(candidate, otherCandidate); | |
836 | break; | |
837 | } | |
838 | } | |
839 | } | |
840 | ||
841 | if (!usableIndex) | |
842 | break; | |
843 | } | |
844 | } | |
845 | ||
846 | if (!usableIndex) | |
847 | continue; | |
848 | ||
802 | 849 | // Looks like we can do a navigational walk. Remember this candidate |
803 | 850 | // and compare it against other possible candidates. |
804 | 851 | |
852 | if (!candidate) | |
853 | { | |
854 | // If no inversion candidate is found, create a fake one representing full index scan | |
855 | ||
856 | candidate = FB_NEW_POOL(pool) InversionCandidate(pool); | |
857 | candidate->cost = indexScratch->cardinality; | |
858 | candidate->indexes = 1; | |
859 | candidate->scratch = indexScratch; | |
860 | candidate->nonFullMatchedSegments = (int) indexScratch->segments.getCount(); | |
861 | } | |
862 | ||
805 | 863 | if (!navigationCandidate) |
806 | navigationCandidate = indexScratch; | |
807 | else | |
808 | { | |
809 | int count1 = MAX(indexScratch->lowerCount, indexScratch->upperCount); | |
810 | int count2 = MAX(navigationCandidate->lowerCount, navigationCandidate->upperCount); | |
811 | ||
812 | if (count1 > count2) | |
813 | navigationCandidate = indexScratch; | |
814 | else if (count1 == count2) | |
815 | { | |
816 | count1 = (int) indexScratch->segments.getCount(); | |
817 | count2 = (int) navigationCandidate->segments.getCount(); | |
818 | ||
819 | if (count1 < count2) | |
820 | navigationCandidate = indexScratch; | |
821 | else if (count1 == count2) | |
864 | navigationCandidate = candidate; | |
865 | else if (betterInversion(candidate, navigationCandidate)) | |
866 | navigationCandidate = candidate; | |
867 | } | |
868 | } | |
869 | ||
870 | bool OptimizerRetrieval::betterInversion(const InversionCandidate* inv1, const InversionCandidate* inv2) const | |
871 | { | |
872 | // Return true if inversion1 is *better* than inversion2. | |
873 | // It's mostly about the retrieval cost, but other aspects are also taken into account. | |
874 | ||
875 | if (inv1->unique && !inv2->unique) | |
876 | { | |
877 | // A unique full equal match is better than anything else. | |
878 | return true; | |
879 | } | |
880 | ||
881 | if (inv1->unique == inv2->unique) | |
882 | { | |
883 | if (inv1->dependencies > inv2->dependencies) | |
884 | { | |
885 | // Index used for a relationship must be always prefered to | |
886 | // the filtering ones, otherwise the nested loop join has | |
887 | // no chances to be better than a sort merge. | |
888 | // An alternative (simplified) condition might be: | |
889 | // currentInv->dependencies > 0 | |
890 | // && bestCandidate->dependencies == 0 | |
891 | // but so far I tend to think that the current one is better. | |
892 | return true; | |
893 | } | |
894 | ||
895 | if (inv1->dependencies == inv2->dependencies) | |
896 | { | |
897 | const double cardinality = | |
898 | MAX(csb->csb_rpt[stream].csb_cardinality, MINIMUM_CARDINALITY); | |
899 | ||
900 | const double cost1 = | |
901 | inv1->cost + (inv1->selectivity * cardinality); | |
902 | const double cost2 = | |
903 | inv2->cost + (inv2->selectivity * cardinality); | |
904 | ||
905 | // Do we have very similar costs? | |
906 | double diffCost = 0; | |
907 | if (!cost1 && !cost2) | |
908 | { | |
909 | // Two zero costs should be handled as being the same | |
910 | // (other comparison criteria should be applied, see below). | |
911 | diffCost = 1; | |
912 | } | |
913 | else if (cost1) | |
914 | { | |
915 | // Calculate the difference | |
916 | diffCost = cost2 / cost1; | |
917 | } | |
918 | ||
919 | if ((diffCost >= 0.98) && (diffCost <= 1.02)) | |
920 | { | |
921 | // If the "same" costs then compare with the nr of unmatched segments, | |
922 | // how many indexes and matched segments. First compare number of indexes. | |
923 | int compareSelectivity = (inv1->indexes - inv2->indexes); | |
924 | ||
925 | if (compareSelectivity == 0) | |
822 | 926 | { |
823 | count1 = BTR_key_length(tdbb, relation, indexScratch->idx); | |
824 | count2 = BTR_key_length(tdbb, relation, navigationCandidate->idx); | |
825 | ||
826 | if (count1 < count2) | |
827 | navigationCandidate = indexScratch; | |
927 | // For the same number of indexes compare number of matched segments. | |
928 | // Note the inverted condition: the more matched segments the better. | |
929 | compareSelectivity = | |
930 | (inv2->matchedSegments - inv1->matchedSegments); | |
931 | ||
932 | if (compareSelectivity == 0) | |
933 | { | |
934 | // For the same number of matched segments | |
935 | // compare ones that aren't full matched | |
936 | compareSelectivity = | |
937 | (inv1->nonFullMatchedSegments - inv2->nonFullMatchedSegments); | |
938 | } | |
828 | 939 | } |
829 | } | |
830 | } | |
831 | } | |
940 | ||
941 | if (compareSelectivity < 0) | |
942 | return true; | |
943 | } | |
944 | else if (cost1 < cost2) | |
945 | return true; | |
946 | } | |
947 | } | |
948 | ||
949 | return false; | |
832 | 950 | } |
833 | 951 | |
834 | 952 | void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversions, |
1258 | 1376 | // Force to always choose at least one index |
1259 | 1377 | bool firstCandidate = true; |
1260 | 1378 | |
1261 | FB_SIZE_T i = 0; | |
1262 | 1379 | InversionCandidate* invCandidate = NULL; |
1263 | InversionCandidate** inversion = inversions->begin(); | |
1264 | for (i = 0; i < inversions->getCount(); i++) | |
1265 | { | |
1266 | inversion[i]->used = false; | |
1267 | const IndexScratch* const indexScratch = inversion[i]->scratch; | |
1380 | ||
1381 | for (InversionCandidate** iter = inversions->begin(); | |
1382 | iter != inversions->end(); ++iter) | |
1383 | { | |
1384 | InversionCandidate* const inversion = *iter; | |
1385 | ||
1386 | inversion->used = (inversion == navigationCandidate); | |
1387 | ||
1388 | const IndexScratch* const indexScratch = inversion->scratch; | |
1268 | 1389 | |
1269 | 1390 | if (indexScratch && |
1270 | (indexScratch == navigationCandidate || | |
1271 | (indexScratch->idx->idx_runtime_flags & idx_plan_dont_use))) | |
1272 | { | |
1273 | inversion[i]->used = true; | |
1391 | (indexScratch->idx->idx_runtime_flags & idx_plan_dont_use)) | |
1392 | { | |
1393 | inversion->used = true; | |
1274 | 1394 | } |
1275 | 1395 | } |
1276 | 1396 | |
1277 | 1397 | // The matches returned in this inversion are always sorted. |
1278 | SortedArray<BoolExprNode*> matches, navigationMatches; | |
1398 | SortedArray<BoolExprNode*> matches; | |
1279 | 1399 | |
1280 | 1400 | if (navigationCandidate) |
1281 | 1401 | { |
1282 | const int matchedSegments = | |
1283 | MAX(navigationCandidate->lowerCount, navigationCandidate->upperCount); | |
1284 | ||
1285 | fb_assert(matchedSegments <= (int) navigationCandidate->segments.getCount()); | |
1286 | ||
1287 | for (int segno = 0; segno < matchedSegments; segno++) | |
1288 | { | |
1289 | const IndexScratchSegment* const segment = navigationCandidate->segments[segno]; | |
1290 | ||
1291 | for (FB_SIZE_T j = 0; j < segment->matches.getCount(); j++) | |
1292 | { | |
1293 | if (!navigationMatches.exist(segment->matches[j])) | |
1294 | navigationMatches.add(segment->matches[j]); | |
1295 | } | |
1296 | } | |
1297 | ||
1298 | matches.join(navigationMatches); | |
1299 | ||
1300 | // If the navigational candidate includes any matching segments, | |
1301 | // reset the selectivity/cost prerequisites to account these matches | |
1302 | if (matchedSegments) | |
1303 | { | |
1304 | totalSelectivity = navigationCandidate->selectivity; | |
1305 | totalIndexCost = DEFAULT_INDEX_COST + totalSelectivity * navigationCandidate->cardinality; | |
1306 | previousTotalCost = totalIndexCost + totalSelectivity * streamCardinality; | |
1402 | matches.join(navigationCandidate->matches); | |
1403 | ||
1404 | // Reset the selectivity/cost prerequisites to account the navigational candidate | |
1405 | totalSelectivity = navigationCandidate->selectivity; | |
1406 | totalIndexCost = navigationCandidate->cost; | |
1407 | previousTotalCost = totalIndexCost + totalSelectivity * streamCardinality; | |
1408 | ||
1409 | if (navigationCandidate->matchedSegments) | |
1307 | 1410 | firstCandidate = false; |
1308 | } | |
1309 | } | |
1310 | ||
1311 | for (i = 0; i < inversions->getCount(); i++) | |
1411 | } | |
1412 | ||
1413 | for (FB_SIZE_T i = 0; i < inversions->getCount(); i++) | |
1312 | 1414 | { |
1313 | 1415 | // Initialize vars before walking through candidates |
1314 | 1416 | InversionCandidate* bestCandidate = NULL; |
1316 | 1418 | |
1317 | 1419 | for (FB_SIZE_T currentPosition = 0; currentPosition < inversions->getCount(); ++currentPosition) |
1318 | 1420 | { |
1319 | InversionCandidate* currentInv = inversion[currentPosition]; | |
1421 | InversionCandidate* currentInv = (*inversions)[currentPosition]; | |
1320 | 1422 | if (!currentInv->used) |
1321 | 1423 | { |
1322 | 1424 | // If this is a unique full equal matched inversion we're done, so |
1323 | 1425 | // we can make the inversion and return it. |
1324 | if (currentInv->unique && currentInv->dependencies && !currentInv->condition && | |
1325 | currentInv->scratch != navigationCandidate) | |
1426 | if (currentInv->unique && currentInv->dependencies && !currentInv->condition) | |
1326 | 1427 | { |
1327 | 1428 | if (!invCandidate) |
1328 | 1429 | invCandidate = FB_NEW_POOL(pool) InversionCandidate(pool); |
1367 | 1468 | if (matches.exist(currentInv->matches[k])) |
1368 | 1469 | { |
1369 | 1470 | anyMatchAlreadyUsed = true; |
1370 | if (navigationMatches.exist(currentInv->matches[k])) | |
1471 | ||
1472 | if (navigationCandidate && | |
1473 | navigationCandidate->matches.exist(currentInv->matches[k])) | |
1474 | { | |
1371 | 1475 | matchUsedByNavigation = true; |
1476 | } | |
1477 | ||
1372 | 1478 | break; |
1373 | 1479 | } |
1374 | 1480 | } |
1376 | 1482 | if (anyMatchAlreadyUsed && !customPlan) |
1377 | 1483 | { |
1378 | 1484 | currentInv->used = true; |
1485 | ||
1379 | 1486 | if (matchUsedByNavigation) |
1380 | 1487 | continue; |
1488 | ||
1381 | 1489 | // If a match on this index was already used by another |
1382 | 1490 | // index, add also the other matches from this index. |
1383 | 1491 | for (FB_SIZE_T j = 0; j < currentInv->matches.getCount(); j++) |
1385 | 1493 | if (!matches.exist(currentInv->matches[j])) |
1386 | 1494 | matches.add(currentInv->matches[j]); |
1387 | 1495 | } |
1496 | ||
1388 | 1497 | // Restart loop, because other indexes could also be excluded now. |
1389 | 1498 | restartLoop = true; |
1390 | 1499 | break; |
1412 | 1521 | break; |
1413 | 1522 | } |
1414 | 1523 | |
1415 | if (currentInv->unique && !bestCandidate->unique) | |
1416 | { | |
1417 | // A unique full equal match is better than anything else. | |
1524 | if (betterInversion(currentInv, bestCandidate)) | |
1418 | 1525 | bestCandidate = currentInv; |
1419 | } | |
1420 | else if (currentInv->unique == bestCandidate->unique) | |
1421 | { | |
1422 | if (currentInv->dependencies > bestCandidate->dependencies) | |
1423 | { | |
1424 | // Index used for a relationship must be always prefered to | |
1425 | // the filtering ones, otherwise the nested loop join has | |
1426 | // no chances to be better than a sort merge. | |
1427 | // An alternative (simplified) condition might be: | |
1428 | // currentInv->dependencies > 0 | |
1429 | // && bestCandidate->dependencies == 0 | |
1430 | // but so far I tend to think that the current one is better. | |
1431 | bestCandidate = currentInv; | |
1432 | } | |
1433 | else if (currentInv->dependencies == bestCandidate->dependencies) | |
1434 | { | |
1435 | ||
1436 | const double bestCandidateCost = | |
1437 | bestCandidate->cost + (bestCandidate->selectivity * streamCardinality); | |
1438 | const double currentCandidateCost = | |
1439 | currentInv->cost + (currentInv->selectivity * streamCardinality); | |
1440 | ||
1441 | // Do we have very similar costs? | |
1442 | double diffCost = currentCandidateCost; | |
1443 | if (!diffCost && !bestCandidateCost) | |
1444 | { | |
1445 | // Two zero costs should be handled as being the same | |
1446 | // (other comparison criteria should be applied, see below). | |
1447 | diffCost = 1; | |
1448 | } | |
1449 | else if (diffCost) | |
1450 | { | |
1451 | // Calculate the difference. | |
1452 | diffCost = bestCandidateCost / diffCost; | |
1453 | } | |
1454 | else { | |
1455 | diffCost = 0; | |
1456 | } | |
1457 | ||
1458 | if ((diffCost >= 0.98) && (diffCost <= 1.02)) | |
1459 | { | |
1460 | // If the "same" costs then compare with the nr of unmatched segments, | |
1461 | // how many indexes and matched segments. First compare number of indexes. | |
1462 | int compareSelectivity = (currentInv->indexes - bestCandidate->indexes); | |
1463 | if (compareSelectivity == 0) | |
1464 | { | |
1465 | // For the same number of indexes compare number of matched segments. | |
1466 | // Note the inverted condition: the more matched segments the better. | |
1467 | compareSelectivity = | |
1468 | (bestCandidate->matchedSegments - currentInv->matchedSegments); | |
1469 | if (compareSelectivity == 0) | |
1470 | { | |
1471 | // For the same number of matched segments | |
1472 | // compare ones that aren't full matched | |
1473 | compareSelectivity = | |
1474 | (currentInv->nonFullMatchedSegments - bestCandidate->nonFullMatchedSegments); | |
1475 | } | |
1476 | } | |
1477 | if (compareSelectivity < 0) { | |
1478 | bestCandidate = currentInv; | |
1479 | } | |
1480 | } | |
1481 | else if (currentCandidateCost < bestCandidateCost) | |
1482 | { | |
1483 | // How lower the cost the better. | |
1484 | bestCandidate = currentInv; | |
1485 | } | |
1486 | } | |
1487 | } | |
1488 | 1526 | } |
1489 | 1527 | } |
1490 | 1528 | } |
1636 | 1674 | |
1637 | 1675 | // If we have no index used for filtering, but there's a navigational walk, |
1638 | 1676 | // set up the inversion candidate appropriately. |
1677 | ||
1639 | 1678 | if (navigationCandidate) |
1640 | 1679 | { |
1641 | 1680 | if (!invCandidate) |
1642 | 1681 | invCandidate = FB_NEW_POOL(pool) InversionCandidate(pool); |
1643 | 1682 | |
1683 | invCandidate->unique = navigationCandidate->unique; | |
1644 | 1684 | invCandidate->selectivity *= navigationCandidate->selectivity; |
1645 | invCandidate->cost += DEFAULT_INDEX_COST + | |
1646 | navigationCandidate->cardinality * navigationCandidate->selectivity; | |
1685 | invCandidate->cost += navigationCandidate->cost; | |
1647 | 1686 | ++invCandidate->indexes; |
1648 | 1687 | invCandidate->navigated = true; |
1649 | 1688 | } |
1650 | 1689 | |
1651 | if (invCandidate && matches.getCount()) | |
1690 | if (invCandidate) | |
1652 | 1691 | invCandidate->matches.join(matches); |
1653 | 1692 | |
1654 | 1693 | return invCandidate; |
179 | 179 | IndexTableScan* getNavigation(); |
180 | 180 | |
181 | 181 | protected: |
182 | void analyzeNavigation(); | |
182 | void analyzeNavigation(const InversionCandidateList& inversions); | |
183 | bool betterInversion(const InversionCandidate* inv1, const InversionCandidate* inv2) const; | |
183 | 184 | InversionNode* composeInversion(InversionNode* node1, InversionNode* node2, |
184 | 185 | InversionNode::Type node_type) const; |
185 | 186 | const Firebird::string& getAlias(); |
221 | 222 | bool outerFlag; |
222 | 223 | bool createIndexScanNodes; |
223 | 224 | bool setConjunctionsMatched; |
224 | IndexScratch* navigationCandidate; | |
225 | InversionCandidate* navigationCandidate; | |
225 | 226 | }; |
226 | 227 | |
227 | 228 | class IndexRelationship |
2 | 2 | *** DO NOT EDIT *** |
3 | 3 | TO CHANGE ANY INFORMATION IN HERE PLEASE |
4 | 4 | EDIT src/misc/writeBuildNum.sh |
5 | FORMAL BUILD NUMBER:33077 | |
5 | FORMAL BUILD NUMBER:33083 | |
6 | 6 | */ |
7 | 7 | |
8 | #define PRODUCT_VER_STRING "3.0.5.33077" | |
9 | #define FILE_VER_STRING "WI-V3.0.5.33077" | |
10 | #define LICENSE_VER_STRING "WI-V3.0.5.33077" | |
11 | #define FILE_VER_NUMBER 3, 0, 5, 33077 | |
8 | #define PRODUCT_VER_STRING "3.0.5.33083" | |
9 | #define FILE_VER_STRING "WI-V3.0.5.33083" | |
10 | #define LICENSE_VER_STRING "WI-V3.0.5.33083" | |
11 | #define FILE_VER_NUMBER 3, 0, 5, 33083 | |
12 | 12 | #define FB_MAJOR_VER "3" |
13 | 13 | #define FB_MINOR_VER "0" |
14 | 14 | #define FB_REV_NO "5" |
15 | #define FB_BUILD_NO "33077" | |
15 | #define FB_BUILD_NO "33083" | |
16 | 16 | #define FB_BUILD_TYPE "V" |
17 | 17 | #define FB_BUILD_SUFFIX "Firebird 3.0" |
1296 | 1296 | if (!*object_name) |
1297 | 1297 | return 0; |
1298 | 1298 | |
1299 | const Jrd::SecurityClass* s_class = SCL_recompute_class(tdbb, object_name); | |
1299 | const Jrd::SecurityClass* s_class = SCL_get_class(tdbb, object_name); | |
1300 | 1300 | if (s_class) |
1301 | 1301 | return s_class->scl_flags; |
1302 | 1302 |